OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
lablib3.c
Go to the documentation of this file.
1 /*========================================================================*/
2 /* */
3 /* PDS Label Library Lite */
4 /* (lablib3) */
5 /* */
6 /* Version: */
7 /* */
8 /* 1.0Beta Mar 31, 1994 */
9 /* 1.0 Jan 23, 1995 */
10 /* 1.1 Feb 23, 1995 */
11 /* 1.2 Jun 06, 1995 Preliminary */
12 /* */
13 /* Change History: */
14 /* */
15 /* 03-31-94 Original code */
16 /* 01-09-95 jsh - Changed OBJECT to OBJDESC */
17 /* 01-09-95 jsh - Corrected strcmp and strncmp == NULL */
18 /* 02-16-95 jsh - Applied LASP changes (from OA dvlp - s. monk) */
19 /* - Function Prototypes */
20 /* - Filename Units */
21 /* - Filename for SUN/Unix */
22 /* - TB_MAX_BUFFER */
23 /* - Several 0 -> NULL in function calls */
24 /* 02-20-95 jsh - Added OdlPrintLine (reduced # fprintf) */
25 /* 06-06-95 jsh/gmw - Allow SFDU without "= SFDU" */
26 /* 06-06-95 jsh/gmw - Stop gap for '/' followed by '*' in text strings */
27 /* */
28 /* */
29 /*========================================================================*/
30 
31 #include "lablib3.h"
32 
33 long odl_message_count = {0};
35 
36 
37 
38 
39 
40 /*========================================================================*/
41 /* */
42 /* Label Parse routines */
43 /* */
44 /*========================================================================*/
45 
46 
47 
48 /************************************************************************/
49 /* */
50 /* Component: */
51 /* */
52 /* OdlParseLabelFile */
53 /* */
54 /* Author: */
55 /* */
56 /* David P. Bernath (Jet Propulsion Laboratory) */
57 /* */
58 /* Version: */
59 /* */
60 /* 1.0 March 31, 1994 */
61 /* */
62 /* Change History: */
63 /* */
64 /* 03-31-94 Original code */
65 /* */
66 /*----------------------------------------------------------------------*/
67 /* */
68 /* Description: */
69 /* */
70 /* This routine causes a file containing a PDS label to be parsed */
71 /* and its "^" keywords expanded. It returns a pointer to the */
72 /* root of the OBJECT tree data structure. */
73 /* */
74 /* The "filespec" parameter is the full path and name of the */
75 /* label file to be parsed. */
76 /* */
77 /* The "message_fname" parameter is the name of the file where */
78 /* parser error messages will be written. If the file exists, */
79 /* the messages are appended, otherwise a new file is created. */
80 /* A NULL value passed in causes messages to be sent to stdout. */
81 /* */
82 /* The "suppress_messages" parameter is a flag that tells the code */
83 /* whether or not to print parser error messages. A value of TRUE */
84 /* (1) tells the code to supress all messages. If this parameter */
85 /* is 1, it doesn't matter what you specified with the */
86 /* "message_fname". Nothing will be written to that file. If a */
87 /* zero (0) is passed in, then messages will be written to the */
88 /* file you specified with the "message_fname" parameter. */
89 /* */
90 /* The expand parameter is a flag that controls whether or not */
91 /* ^STRUCTURE and ^CATALOG keywords are expanded. To expand one */
92 /* of these keywords means to take the file name it points to, */
93 /* parse its contents, and insert the results into the tree right */
94 /* where the keyword is sitting. In other words, these keywords */
95 /* function just like include files in "C". These are the values */
96 /* that can be passed in: */
97 /* */
98 /* ODL_EXPAND_STRUCTURE - expand ^STRUCTURE keywords only */
99 /* ODL_EXPAND_CATALOG - expand ^CATALOG keywords only */
100 /* ODL_EXPAND_STRUCTURE | ODL_EXPAND_CATALOG - expand */
101 /* both keywords (the "|" character is the logical */
102 /* "or" of both values). */
103 /* */
104 /*----------------------------------------------------------------------*/
105 /* */
106 /* WARNING: The value returned by this routine points to memory */
107 /* allocated by this routine (sometimes quite a bit of */
108 /* memory!). Be sure to deallocate it using the */
109 /* OdlFreeTree routine. */
110 /* */
111 /************************************************************************/
112 
113 #ifdef _NO_PROTO
114 
115 OBJDESC *OdlParseLabelFile (filespec, message_fname, expand, suppress_messages)
116 
117 char *filespec;
118 char *message_fname;
119 MASK expand;
120 unsigned short suppress_messages;
121 
122 #else
123 
124 OBJDESC *OdlParseLabelFile (char *filespec, char *message_fname, MASK expand,
125  unsigned short suppress_messages)
126 
127 #endif
128 
129 {
130  OBJDESC *root = {NULL};
131 
132  odl_suppress_messages = suppress_messages;
133  root = (OBJDESC *) OdlParseFile(filespec,NULL,message_fname,NULL,suppress_messages,1,1,0);
134  root = (OBJDESC *) OdlExpandLabelFile(root, message_fname, expand,
135  suppress_messages);
136 
137  return(root);
138 
139 } /* End: "OdlParseLabelFile" */
140 
141 
142 
143 
144 /************************************************************************/
145 /* */
146 /* Component: */
147 /* */
148 /* OdlParseLabelString */
149 /* */
150 /* Author: */
151 /* */
152 /* David P. Bernath (Jet Propulsion Laboratory) */
153 /* */
154 /* Version: */
155 /* */
156 /* 1.0 March 31, 1994 */
157 /* */
158 /* Change History: */
159 /* */
160 /* 03-31-94 Original code */
161 /* */
162 /*----------------------------------------------------------------------*/
163 /* */
164 /* Description: */
165 /* */
166 /* This routine causes a character string containing an ODL */
167 /* statement to be parsed and its "^" keywords expanded. It */
168 /* returns a pointer to the root of the OBJECT tree data structure.*/
169 /* */
170 /* WARNING: The value returned by this routine points to memory */
171 /* allocated by this routine. Be sure to deallocate it */
172 /* using the OdlFreeTree routine. */
173 /* */
174 /* WARNING: This routine will try to create a temporary file in */
175 /* the following locations, depending on the system: */
176 /* */
177 /* UNIX: ~/<tmp fname>.tmp */
178 /* VMS: sys$login:<tmp fname>.tmp */
179 /* MSDOS: C:<tmp fname>.tmp */
180 /* All others: <tmp fname>.tmp */
181 /* */
182 /************************************************************************/
183 
184 #ifdef _NO_PROTO
185 
186 OBJDESC *OdlParseLabelString (odl_string, message_fname,
187  expand, suppress_messages)
188 
189 char *odl_string;
190 char *message_fname;
191 MASK expand;
192 unsigned short suppress_messages;
193 
194 #else
195 
196 OBJDESC *OdlParseLabelString (char *odl_string, char *message_fname,
197  MASK expand, unsigned short suppress_messages)
198 
199 #endif
200 {
201  OBJDESC *root = {NULL};
202  FILE *tmp_fptr = {NULL};
203  char *tmp_fname = {NULL};
204 
205  odl_suppress_messages = suppress_messages;
206 
207  tmp_fname = (char *) OdlTempFname();
208 
209  if (tmp_fname == NULL)
210  (void)OdlPrintMessage(message_fname,NULL,0,"Unable to create a temporary file");
211 
212  if ((tmp_fptr = (FILE *) fopen(tmp_fname, "w")) != NULL)
213  {
214  (void)fprintf(tmp_fptr, "%s", odl_string);
215  (void)fclose(tmp_fptr);
216  root = (OBJDESC *) OdlParseLabelFile(tmp_fname, message_fname,
217  expand, suppress_messages);
218 #ifdef VMS
219  AppendString(tmp_fname, ";*")
220 #endif
221  (void)remove(tmp_fname);
222  }
223 
224  LemmeGo(tmp_fname)
225 
226  return(root);
227 
228 } /* End: "OdlParseLabelString" */
229 
230 
231 
232 
233 /*========================================================================*/
234 /* */
235 /* Label Expand routines */
236 /* */
237 /*========================================================================*/
238 
239 /************************************************************************/
240 /* */
241 /* Component: */
242 /* */
243 /* OdlExpandLabelFile */
244 /* */
245 /* Author: */
246 /* */
247 /* David P. Bernath (Jet Propulsion Laboratory) */
248 /* */
249 /* Version: */
250 /* */
251 /* 1.0 March 31, 1994 */
252 /* */
253 /* Change History: */
254 /* */
255 /* 03-31-94 Original code */
256 /* */
257 /*----------------------------------------------------------------------*/
258 /* */
259 /* Description: */
260 /* */
261 /* This routine locates "^STRUCTURE" and "^CATALOG" keywords and */
262 /* expands them. To "expand" means to extract the file name */
263 /* pointed to by the keyword, parse its contents, and insert the */
264 /* resulting tree into the label right where the keyword is */
265 /* sitting. */
266 /* */
267 /************************************************************************/
268 
269 #ifdef _NO_PROTO
270 
271 OBJDESC *OdlExpandLabelFile (object, message_fname, expand, suppress_messages)
272 
273 OBJDESC *object;
274 char *message_fname;
275 MASK expand;
276 unsigned short suppress_messages;
277 
278 #else
279 
280 OBJDESC *OdlExpandLabelFile (OBJDESC *object, char *message_fname, MASK expand,
281  unsigned short suppress_messages)
282 
283 #endif
284 {
285  KEYWORD *kwd = {NULL};
286  KEYWORD *new_kwd = {NULL};
287  KEYWORD *save_kwd = {NULL};
288  OBJDESC *temp_root = {NULL};
289  OBJDESC *new_obj = {NULL};
290  OBJDESC *save_obj = {NULL};
291  FILE *l_ptr = {NULL};
292  unsigned long start_loc = {1};
293  unsigned short loc_type = {ODL_RECORD_LOCATION};
294  unsigned short done = {FALSE};
295  char *fspec = {NULL};
296  char *fname = {NULL};
297  char *keyword_name = {NULL};
298  char error_message[5*(TB_MAXLINE + TB_MAXPATH + TB_MAXFNAME)];
299 
300  odl_suppress_messages = suppress_messages;
301 
302  /* Let's expand all ^STRUCTURE keywords, shall we? */
304  {
305  expand -= ODL_EXPAND_STRUCTURE;
306  CopyString(keyword_name, "^*STRUCTURE")
307  }
308  else
309  /* On second thought, let's expand all ^CATALOG keywords */
310  if ((expand&ODL_EXPAND_CATALOG) == ODL_EXPAND_CATALOG)
311  {
312  expand -= ODL_EXPAND_CATALOG;
313  CopyString(keyword_name, "^*CATALOG")
314  }
315  else
316  /* Hmmm. I guess we have nothing left to expand. */
317  {
318  expand = ODL_NOEXPAND;
319  done = TRUE;
320  }
321 
322  /* Keep expanding until we can expand no more forever */
323  while (! done)
324  {
325  /* Find the expand keyword wherever it my be hiding */
326  kwd = (KEYWORD *) OdlFindKwd(object, keyword_name,
328 
329  /* We're done if there aren't any more keywords to expand */
330  if (kwd == NULL)
331  done = TRUE;
332  else
333  {
334  /* Get the file name, minus quotes and blanks, sans path */
335  fname = (char *) OdlGetFileName(kwd, &start_loc, &loc_type);
336 
337  /* We're in trouble if we've encountered this file before */
338  if (ExpandIsRecursive(kwd, fname))
339  {
340  (void)sprintf(error_message,
341  "Recursive %s statement found in file: %s",
342  keyword_name, fname);
343  (void)OdlPrintMessage(message_fname,NULL,(long)kwd->line_number,error_message);
344  }
345  else
346  {
347  /* Figure out exactly where the file is located */
348  fspec = (char *) OdlGetFileSpec(fname);
349 
350  /* We're in trouble if we can't find the file */
351  if (fspec == NULL)
352  {
353  (void)sprintf(error_message,
354  "Unable to locate %s file: %s",
355  keyword_name, fname);
356  (void)OdlPrintMessage(message_fname,NULL,(long)kwd->line_number,error_message);
357  }
358  else
359  {
360  l_ptr = (FILE *) OdlLocateStart(fspec, start_loc, loc_type);
361 
362 
363  /* Parse the file */
364  temp_root = (OBJDESC *) OdlParseFile(fspec,l_ptr,
365  message_fname,NULL,0,1,1,1);
366 
367  /* Was there anything in the file to parse? */
368  if (temp_root != NULL)
369  {
370  /* Append any keywords */
371  for (new_kwd=temp_root->first_keyword;
372  new_kwd != NULL; new_kwd = save_kwd)
373  {
374  save_kwd = new_kwd->right_sibling;
375  (void)OdlPasteKwd((KEYWORD *) OdlCutKwd(new_kwd),
376  kwd->parent);
377  }
378 
379  /* Append any sub-objects */
380  for (new_obj=temp_root->first_child;
381  new_obj != NULL; new_obj = save_obj)
382  {
383  save_obj = new_obj->right_sibling;
384  (void)OdlPasteObjDesc((OBJDESC *) OdlCutObjDesc(new_obj),
385  kwd->parent);
386  }
387 
388  /* Deallocate the temporary root */
389  temp_root->first_keyword = NULL;
390  temp_root->first_child = NULL;
391  temp_root = (OBJDESC *) OdlFreeTree(temp_root);
392 
393  } /* End: "if (temp_root != NULL) ..." */
394 
395  /* Free the file spec storage */
396  LemmeGo(fspec)
397 
398  } /* End: "if (fspec == NULL) ... else ..." */
399 
400  } /* End: "if (ExpandIsRecursive( ... else ..." */
401 
402  (void)OdlFreeKwd((KEYWORD *)OdlCutKwd(kwd));
403 
404  /* Free the file name storage */
405  LemmeGo(fname)
406 
407  } /* End: "if (kwd == NULL) ... else ..." */
408 
409  } /* End: "while (! done) ..." */
410 
411  /* Free the keyword name storage */
412  LemmeGo(keyword_name)
413 
414  /* Check and see if there are any other keywords to expand */
415  if (expand != ODL_NOEXPAND)
416  {
417  object = (OBJDESC *) OdlExpandLabelFile(object, message_fname,
418  expand, suppress_messages);
419  }
420 
421  /* Return the root of the expanded tree */
422  return(object);
423 
424 } /* End: "OdlExpandLabelFile" */
425 
426 
427 
428 /*******************/
429 /* Local Routine */
430 /*******************/
431 
432 #ifdef _NO_PROTO
433 
434 unsigned short ExpandIsRecursive (keyword, exp_fname)
435 
436 KEYWORD *keyword;
437 char *exp_fname;
438 
439 #else
440 
441 unsigned short ExpandIsRecursive (KEYWORD *keyword, char *exp_fname)
442 
443 #endif
444 {
445  OBJDESC *obj = {NULL};
446  char *temp_fname = {NULL};
447  unsigned short found = {FALSE};
448 
449  if ((keyword != NULL) && (exp_fname != NULL))
450  {
451 #if (defined( VAX) || defined( ALPHA_VMS))
452  UpperCase(exp_fname)
453 #endif
454 
455  CopyString(temp_fname, keyword->file_name)
456 
457 #if (defined( VAX) || defined( ALPHA_VMS))
458  UpperCase(temp_fname)
459 #endif
460 
461  found = (strcmp(temp_fname, exp_fname) == 0);
462  LemmeGo(temp_fname)
463 
464  for (obj=keyword->parent;
465  ((! found) && (obj != NULL)); obj=obj->parent)
466  {
467  CopyString(temp_fname, obj->file_name)
468 
469 #if (defined( VAX) || defined( ALPHA_VMS))
470  UpperCase(temp_fname)
471 #endif
472 
473  found = (strcmp(temp_fname, exp_fname) == 0);
474  LemmeGo(temp_fname)
475  }
476  }
477 
478  return(found);
479 
480 } /* End: "ExpandIsRecursive" */
481 
482 
483 
484 
485 
486 /*========================================================================*/
487 /* */
488 /* Object description routines */
489 /* */
490 /*========================================================================*/
491 
492 /************************************************************************/
493 /* */
494 /* Component: */
495 /* */
496 /* OdlFindObjDesc */
497 /* */
498 /* Author: */
499 /* */
500 /* David P. Bernath (Jet Propulsion Laboratory) */
501 /* */
502 /* Version: */
503 /* */
504 /* 1.0 March 31, 1994 */
505 /* */
506 /* Change History: */
507 /* */
508 /* 03-31-94 Original code */
509 /* */
510 /*----------------------------------------------------------------------*/
511 /* */
512 /* Description: */
513 /* */
514 /* This routine locates an object within a parsed label by its */
515 /* class name (like TABLE), by its position (look for the seventh */
516 /* table object in the label), by a particular keyword present */
517 /* in the object (like NAME), or by a particular value that a */
518 /* particular keyword has (like START_BYTE = 76). */
519 /* */
520 /************************************************************************/
521 
522 #ifdef _NO_PROTO
523 
524 OBJDESC *OdlFindObjDesc(start_object, object_class, keyword_name,
525  keyword_value, object_position, search_scope)
526 
527 OBJDESC *start_object;
528 const char *object_class;
529 const char *keyword_name;
530 char *keyword_value;
531 unsigned long object_position;
532 unsigned short search_scope;
533 
534 #else
535 
536 OBJDESC *OdlFindObjDesc( OBJDESC *start_object, const char *object_class,
537  const char *keyword_name, char *keyword_value,
538  unsigned long object_position,
539  unsigned short search_scope)
540 
541 #endif
542 {
543  OBJDESC *found_object = {NULL};
544  OBJDESC *obj = {NULL};
545  KEYWORD *kwd = {NULL};
546  unsigned short found = {FALSE};
547  unsigned short scope = {search_scope};
548  unsigned long current_position = {0};
549 
550  for (obj=start_object;
551  ((obj != NULL) && (! found));
552  obj = (OBJDESC *) OdlNextObjDesc(obj, start_object->level, &scope))
553  {
554  if (object_class == NULL)
555  found = TRUE;
556  else
557  found = OdlWildCardCompare(object_class, obj->class);
558 
559  if ((found) && (keyword_name != NULL))
560  {
561  kwd = (KEYWORD *) OdlFindKwd(obj, keyword_name,
562  NULL, 1, ODL_THIS_OBJECT);
563  found = (kwd != NULL);
564  }
565 
566  if ((found) && (keyword_value != NULL))
567  found = OdlWildCardCompare(keyword_value, (char *) OdlGetKwdValue(kwd));
568 
569  if ((found) && (object_position != 0))
570  found = ((++current_position) == object_position);
571 
572  if (found) found_object = obj;
573 
574  } /* End: "for (obj=start_object; ..." */
575 
576  return(found_object);
577 
578 } /* End: "OdlFindObjDesc" */
579 
580 
581 
582 /************************************************************************/
583 /* */
584 /* Component: */
585 /* */
586 /* OdlNextObjDesc */
587 /* */
588 /* Author: */
589 /* */
590 /* David P. Bernath (Jet Propulsion Laboratory) */
591 /* */
592 /* Version: */
593 /* */
594 /* 1.0 March 31, 1994 */
595 /* */
596 /* Change History: */
597 /* */
598 /* 03-31-94 Original code */
599 /* */
600 /*----------------------------------------------------------------------*/
601 /* */
602 /* Description: */
603 /* */
604 /* This routine locates the next object in the tree based on the */
605 /* search_scope passed in. */
606 /* */
607 /************************************************************************/
608 
609 #ifdef _NO_PROTO
610 
611 OBJDESC *OdlNextObjDesc (object, root_level, search_scope)
612 
613 OBJDESC *object;
614 unsigned long root_level;
615 unsigned short *search_scope;
616 
617 #else
618 
619 OBJDESC *OdlNextObjDesc (OBJDESC *object, unsigned long root_level,
620  unsigned short *search_scope)
621 
622 #endif
623 {
624  OBJDESC *next_object = {NULL};
625 
626  if (object != NULL)
627  {
628  switch (*search_scope)
629  {
630  /* look only in the current object */
631  case ODL_THIS_OBJECT : next_object = NULL;
632  break;
633 
634  /* look at the current object's first child now, and its */
635  /* child's right siblings in subsequent searches */
636  case ODL_CHILDREN_ONLY : next_object = object->first_child;
637  *search_scope = ODL_SIBLINGS_ONLY;
638  break;
639 
640  /* look at the current object's right sibling */
641  case ODL_SIBLINGS_ONLY : next_object = object->right_sibling;
642  break;
643 
644  /* treat the current object as the root of a sub-tree */
645  case ODL_RECURSIVE_DOWN : next_object = (OBJDESC *) OdlTraverseTree(object, root_level);
646  break;
647 
648  /* search children, then siblings, then move up to parent */
649  /* keep going until the end of the label is reached */
650  default : next_object = (OBJDESC *)
651  OdlTraverseTree(object,
652  (unsigned long) 0);
653  break;
654 
655  } /* End: "switch (*search_scope) ..." */
656 
657  } /* End: "if (object != NULL) ..." */
658 
659  return(next_object);
660 
661 } /* End: "OdlNextObjDesc" */
662 
663 
664 
665 /************************************************************************/
666 /* */
667 /* Component: */
668 /* */
669 /* OdlCutObjDesc */
670 /* */
671 /* Author: */
672 /* */
673 /* David P. Bernath (Jet Propulsion Laboratory) */
674 /* */
675 /* Version: */
676 /* */
677 /* 1.0 March 31, 1994 */
678 /* */
679 /* Change History: */
680 /* */
681 /* 03-31-94 Original code */
682 /* */
683 /*----------------------------------------------------------------------*/
684 /* */
685 /* Description: */
686 /* */
687 /* This routine cuts an ODL object structure out of an ODL tree */
688 /* and returns a pointer to it. All references to it in the tree */
689 /* are removed, and all references to the original tree within the */
690 /* object are removed. */
691 /* */
692 /************************************************************************/
693 
694 #ifdef _NO_PROTO
695 
696 OBJDESC *OdlCutObjDesc (object)
697 
698 OBJDESC *object;
699 
700 #else
701 
702 OBJDESC *OdlCutObjDesc (OBJDESC *object)
703 
704 #endif
705 {
706  if (object != NULL)
707  {
708  if (object->right_sibling == NULL)
709  object->parent->last_child = object->left_sibling;
710  else
711  object->right_sibling->left_sibling = object->left_sibling;
712 
713  if (object->left_sibling == NULL)
714  object->parent->first_child = object->right_sibling;
715  else
716  object->left_sibling->right_sibling = object->right_sibling;
717 
718  object->parent = NULL;
719  object->left_sibling = NULL;
720  object->right_sibling = NULL;
721 
722  } /* End: "if (object != NULL) ..." */
723 
724  return(object);
725 
726 } /* End routine: "OdlCutObjDesc" */
727 
728 
729 
730 /************************************************************************/
731 /* */
732 /* Component: */
733 /* */
734 /* OdlPasteObjDesc */
735 /* */
736 /* Author: */
737 /* */
738 /* David P. Bernath (Jet Propulsion Laboratory) */
739 /* */
740 /* Version: */
741 /* */
742 /* 1.0 March 31, 1994 */
743 /* */
744 /* Change History: */
745 /* */
746 /* 03-31-94 Original code */
747 /* */
748 /*----------------------------------------------------------------------*/
749 /* */
750 /* Description: */
751 /* */
752 /* This routine adds an object to a tree as the last child of the */
753 /* parent_object. */
754 /* */
755 /************************************************************************/
756 
757 #ifdef _NO_PROTO
758 
759 OBJDESC *OdlPasteObjDesc (new_object, parent_object)
760 
761 OBJDESC *new_object;
762 OBJDESC *parent_object;
763 
764 #else
765 
766 OBJDESC *OdlPasteObjDesc (OBJDESC *new_object, OBJDESC *parent_object)
767 
768 #endif
769 {
770  if ((new_object != NULL) && (parent_object != NULL))
771  {
772  new_object->left_sibling = parent_object->last_child;
773  new_object->right_sibling = NULL;
774  new_object->parent = parent_object;
775 
776  if (parent_object->first_child == NULL)
777  parent_object->first_child = new_object;
778 
779  if (parent_object->last_child != NULL)
780  parent_object->last_child->right_sibling = new_object;
781 
782  parent_object->last_child = new_object;
783 
784  OdlAdjustObjDescLevel(new_object);
785 
786  } /* End: "if ((new_object != NULL) && ..." */
787 
788  return(new_object);
789 
790 } /* End routine: "OdlPasteObjDesc" */
791 
792 
793 
794 /************************************************************************/
795 /* */
796 /* Component: */
797 /* */
798 /* OdlPasteObjDescBefore */
799 /* */
800 /* Author: */
801 /* */
802 /* David P. Bernath (Jet Propulsion Laboratory) */
803 /* */
804 /* Version: */
805 /* */
806 /* 1.0 March 31, 1994 */
807 /* */
808 /* Change History: */
809 /* */
810 /* 03-31-94 Original code */
811 /* */
812 /*----------------------------------------------------------------------*/
813 /* */
814 /* Description: */
815 /* */
816 /* This routine adds an object to a tree as the left sibling of */
817 /* the old_object. */
818 /* */
819 /************************************************************************/
820 
821 #ifdef _NO_PROTO
822 
823 OBJDESC *OdlPasteObjDescBefore (new_object, old_object)
824 
825 OBJDESC *new_object;
826 OBJDESC *old_object;
827 
828 #else
829 
830 OBJDESC *OdlPasteObjDescBefore (OBJDESC *new_object, OBJDESC *old_object)
831 
832 #endif
833 {
834  if ((new_object != NULL) && (old_object != NULL))
835  {
836  new_object->left_sibling = old_object->left_sibling;
837  new_object->right_sibling = old_object;
838  new_object->parent = old_object->parent;
839 
840  if (old_object->left_sibling == NULL)
841  old_object->parent->first_child = new_object;
842  else
843  old_object->left_sibling->right_sibling = new_object;
844 
845  old_object->left_sibling = new_object;
846 
847  OdlAdjustObjDescLevel(new_object);
848 
849  } /* End: "if ((new_object != NULL) && ..." */
850 
851  return(new_object);
852 
853 } /* End routine: "OdlPasteObjDescBefore" */
854 
855 
856 
857 /************************************************************************/
858 /* */
859 /* Component: */
860 /* */
861 /* OdlPasteObjDescAfter */
862 /* */
863 /* Author: */
864 /* */
865 /* David P. Bernath (Jet Propulsion Laboratory) */
866 /* */
867 /* Version: */
868 /* */
869 /* 1.0 March 31, 1994 */
870 /* */
871 /* Change History: */
872 /* */
873 /* 03-31-94 Original code */
874 /* */
875 /*----------------------------------------------------------------------*/
876 /* */
877 /* Description: */
878 /* */
879 /* This routine adds an object to a tree as the right sibling of */
880 /* the old_object. */
881 /* */
882 /************************************************************************/
883 
884 #ifdef _NO_PROTO
885 
886 OBJDESC *OdlPasteObjDescAfter (new_object, old_object)
887 
888 OBJDESC *new_object;
889 OBJDESC *old_object;
890 
891 #else
892 
893 OBJDESC *OdlPasteObjDescAfter (OBJDESC *new_object, OBJDESC *old_object)
894 
895 #endif
896 {
897  if ((new_object != NULL) && (old_object != NULL))
898  {
899  new_object->right_sibling = old_object->right_sibling;
900  new_object->left_sibling = old_object;
901  new_object->parent = old_object->parent;
902 
903  if (old_object->right_sibling == NULL)
904  old_object->parent->last_child = new_object;
905  else
906  old_object->right_sibling->left_sibling = new_object;
907 
908  old_object->right_sibling = new_object;
909 
910  OdlAdjustObjDescLevel(new_object);
911 
912  } /* End: "if ((new_object != NULL) && ..." */
913 
914  return(new_object);
915 
916 } /* End routine: "OdlPasteObjDescAfter" */
917 
918 
919 
920 /************************************************************************/
921 /* */
922 /* Component: */
923 /* */
924 /* OdlCopyObjDesc */
925 /* */
926 /* Author: */
927 /* */
928 /* David P. Bernath (Jet Propulsion Laboratory) */
929 /* */
930 /* Version: */
931 /* */
932 /* 1.0 March 31, 1994 */
933 /* */
934 /* Change History: */
935 /* */
936 /* 03-31-94 Original code */
937 /* */
938 /*----------------------------------------------------------------------*/
939 /* */
940 /* Description: */
941 /* */
942 /* This routine makes a copy of an object and returns a pointer */
943 /* to the copy. All fields are duplicated except for references */
944 /* to the original tree, which are removed. */
945 /* */
946 /************************************************************************/
947 
948 #ifdef _NO_PROTO
949 
950 OBJDESC *OdlCopyObjDesc (object)
951 
952 OBJDESC *object;
953 
954 #else
955 
956 OBJDESC *OdlCopyObjDesc (OBJDESC *object)
957 
958 #endif
959 {
960  OBJDESC *new_object = {NULL};
961 
962  if (object != NULL)
963  {
964  new_object = OdlNewObjDesc(object->class,
965  object->pre_comment, object->line_comment,
966  object->post_comment, object->end_comment,
967  object->file_name, object->is_a_group,
968  (long)object->line_number);
969  }
970 
971  return(new_object);
972 
973 } /* End routine: "OdlCopyObjDesc" */
974 
975 
976 
977 /************************************************************************/
978 /* */
979 /* Component: */
980 /* */
981 /* OdlNewObjDesc */
982 /* */
983 /* Author: */
984 /* */
985 /* David P. Bernath (Jet Propulsion Laboratory) */
986 /* */
987 /* Version: */
988 /* */
989 /* 1.0 March 31, 1994 */
990 /* */
991 /* Change History: */
992 /* */
993 /* 03-31-94 Original code */
994 /* */
995 /*----------------------------------------------------------------------*/
996 /* */
997 /* Description: */
998 /* */
999 /* This routine creates a new object structure and initializes */
1000 /* its fields with the values passed in. */
1001 /* */
1002 /************************************************************************/
1003 
1004 #ifdef _NO_PROTO
1005 
1006 OBJDESC *OdlNewObjDesc (object_class, pre_comment, line_comment, post_comment,
1007  end_comment, file_name, is_a_group, line_number)
1008 const char *object_class;
1009 const char *pre_comment;
1010 const char *line_comment;
1011 const char *post_comment;
1012 const char *end_comment;
1013 const char *file_name;
1014 short is_a_group;
1015 long line_number;
1016 
1017 #else
1018 
1019 OBJDESC *OdlNewObjDesc (const char *object_class, const char *pre_comment,
1020  const char *line_comment, const char *post_comment,
1021  const char *end_comment, const char *file_name,
1022  short is_a_group, long line_number)
1023 
1024 #endif
1025 {
1026  OBJDESC *new_object = {NULL};
1027 
1028  if ((new_object = (OBJDESC *)malloc(sizeof(OBJDESC))) == NULL)
1029  SayGoodbye()
1030  else
1031  {
1032  CopyString(new_object->class, object_class)
1033  CopyString(new_object->pre_comment, pre_comment)
1034  CopyString(new_object->line_comment, line_comment)
1035  CopyString(new_object->post_comment, post_comment)
1036  CopyString(new_object->end_comment, end_comment)
1037  CopyString(new_object->file_name, file_name)
1038 
1039  new_object->is_a_group = is_a_group;
1040  new_object->child_count = 0;
1041  new_object->line_number = line_number;
1042  new_object->level = 0;
1043  new_object->parent = NULL;
1044  new_object->left_sibling = NULL;
1045  new_object->right_sibling = NULL;
1046  new_object->first_child = NULL;
1047  new_object->last_child = NULL;
1048  new_object->first_keyword = NULL;
1049  new_object->last_keyword = NULL;
1050  new_object->appl1 = NULL;
1051  new_object->appl2 = NULL;
1052 
1053  } /* End: "if ((new_object = ... else ..." */
1054 
1055  return(new_object);
1056 
1057 } /* End routine: "OdlNewObjDesc" */
1058 
1059 
1060 
1061 
1062 /************************************************************************/
1063 /* */
1064 /* Component: */
1065 /* */
1066 /* OdlGetLabelVersion */
1067 /* */
1068 /* Author: */
1069 /* */
1070 /* David P. Bernath (Jet Propulsion Laboratory) */
1071 /* */
1072 /* Version: */
1073 /* */
1074 /* 1.0 March 31, 1994 */
1075 /* */
1076 /* Change History: */
1077 /* */
1078 /* 03-31-94 Original code */
1079 /* */
1080 /*----------------------------------------------------------------------*/
1081 /* */
1082 /* Description: */
1083 /* */
1084 /* This routine returns a pointer to a character string containing */
1085 /* the ODL version of the label. It looks for this information in */
1086 /* the ODL_VERSION_NUMBER keyword. */
1087 /* */
1088 /* WARNING: NO MEMORY IS ALLOCATED BY THIS ROUTINE. THE RETURN */
1089 /* VALUE IS A POINTER TO THE ACTUAL VALUE OF THE */
1090 /* ODL_VERSION_NUMBER KEYWORD AND MUST NOT BE FREED. */
1091 /* */
1092 /************************************************************************/
1093 
1094 #ifdef _NO_PROTO
1095 
1096 char *OdlGetLabelVersion (object)
1097 
1098 OBJDESC *object;
1099 
1100 #else
1101 
1102 char *OdlGetLabelVersion (OBJDESC *object)
1103 
1104 #endif
1105 {
1106  KEYWORD *kwd = {NULL};
1107  char *version = {NULL};
1108 
1109  if (object != NULL)
1110  {
1111  kwd = (KEYWORD *) OdlFindKwd(object, "PDS_VERSION_ID",
1112  NULL, 1, ODL_THIS_OBJECT);
1113  if (kwd == NULL)
1114  {
1115  kwd = (KEYWORD *) OdlFindKwd(object, "ODL_VERSION_NUMBER",
1116  NULL, 1, ODL_THIS_OBJECT);
1117  }
1118 
1119  if (kwd != NULL)
1120  version = (char *) OdlGetKwdValue(kwd);
1121  }
1122 
1123  return(version);
1124 
1125 } /* End: "OdlGetLabelVersion" */
1126 
1127 
1128 
1129 /************************************************************************/
1130 /* */
1131 /* Component: */
1132 /* */
1133 /* OdlGetObjDescClassName */
1134 /* */
1135 /* Author: */
1136 /* */
1137 /* David P. Bernath (Jet Propulsion Laboratory) */
1138 /* */
1139 /* Version: */
1140 /* */
1141 /* 1.0 March 31, 1994 */
1142 /* */
1143 /* Change History: */
1144 /* */
1145 /* 03-31-94 Original code */
1146 /* */
1147 /*----------------------------------------------------------------------*/
1148 /* */
1149 /* Description: */
1150 /* */
1151 /* This routine returns the class name of an object. */
1152 /* */
1153 /* WARNING: NO MEMORY IS ALLOCATED BY THIS ROUTINE. THE RETURN */
1154 /* VALUE IS A POINTER TO THE ACTUAL INFORMATION STORED */
1155 /* IN THE ODL OBJECT STRUCTURE AND MUST NOT BE FREED. */
1156 /* */
1157 /************************************************************************/
1158 
1159 #ifdef _NO_PROTO
1160 
1161 char *OdlGetObjDescClassName (object)
1162 
1163 OBJDESC *object;
1164 
1165 #else
1166 
1167 char *OdlGetObjDescClassName (OBJDESC *object)
1168 
1169 #endif
1170 {
1171  char *class_name = {NULL};
1172 
1173  if (object != NULL)
1174  class_name = object->class;
1175 
1176  return(class_name);
1177 
1178 } /* End: "OdlGetObjDescClassName" */
1179 
1180 
1181 
1182 /************************************************************************/
1183 /* */
1184 /* Component: */
1185 /* */
1186 /* OdlGetObjDescChildCount */
1187 /* */
1188 /* Author: */
1189 /* */
1190 /* David P. Bernath (Jet Propulsion Laboratory) */
1191 /* */
1192 /* Version: */
1193 /* */
1194 /* 1.0 March 31, 1994 */
1195 /* */
1196 /* Change History: */
1197 /* */
1198 /* 03-31-94 Original code */
1199 /* */
1200 /*----------------------------------------------------------------------*/
1201 /* */
1202 /* Description: */
1203 /* */
1204 /* This routine returns a count of the immediate children of an */
1205 /* object. It does not count children of children, etc. */
1206 /* */
1207 /************************************************************************/
1208 
1209 #ifdef _NO_PROTO
1210 
1211 int OdlGetObjDescChildCount (object)
1212 
1213 OBJDESC *object;
1214 
1215 #else
1216 
1217 int OdlGetObjDescChildCount (OBJDESC *object)
1218 
1219 #endif
1220 {
1221  OBJDESC *obj = {NULL};
1222  int child_count = {0};
1223 
1224  if (object != NULL)
1225  {
1226  for (obj=object->first_child; obj != NULL; obj=obj->right_sibling)
1227  ++child_count;
1228  }
1229 
1230  return(child_count);
1231 
1232 } /* End: "OdlGetObjDescChildCount" */
1233 
1234 
1235 
1236 /************************************************************************/
1237 /* */
1238 /* Component: */
1239 /* */
1240 /* OdlGetObjDescLevel */
1241 /* */
1242 /* Author: */
1243 /* */
1244 /* David P. Bernath (Jet Propulsion Laboratory) */
1245 /* */
1246 /* Version: */
1247 /* */
1248 /* 1.0 March 31, 1994 */
1249 /* */
1250 /* Change History: */
1251 /* */
1252 /* 03-31-94 Original code */
1253 /* */
1254 /*----------------------------------------------------------------------*/
1255 /* */
1256 /* Description: */
1257 /* */
1258 /* This routine returns the nesting level of an object. The ROOT */
1259 /* object in a tree is always defined to be level 0. */
1260 /* */
1261 /************************************************************************/
1262 
1263 #ifdef _NO_PROTO
1264 
1265 int OdlGetObjDescLevel (object)
1266 
1267 OBJDESC *object;
1268 
1269 #else
1270 
1271 int OdlGetObjDescLevel (OBJDESC *object)
1272 
1273 #endif
1274 {
1275  OBJDESC *obj = {NULL};
1276  int level = {0};
1277 
1278  if (object != NULL)
1279  {
1280  for (obj=object->parent; obj != NULL; obj=obj->parent)
1281  ++level;
1282  }
1283 
1284  return(level);
1285 
1286 } /* End: "OdlGetObjDescLevel" */
1287 
1288 
1289 
1290 /************************************************************************/
1291 /* */
1292 /* Component: */
1293 /* */
1294 /* OdlAdjustObjDescLevel */
1295 /* */
1296 /* Author: */
1297 /* */
1298 /* David P. Bernath (Jet Propulsion Laboratory) */
1299 /* */
1300 /* Version: */
1301 /* */
1302 /* 1.0 March 31, 1994 */
1303 /* */
1304 /* Change History: */
1305 /* */
1306 /* 03-31-94 Original code */
1307 /* */
1308 /*----------------------------------------------------------------------*/
1309 /* */
1310 /* Description: */
1311 /* */
1312 /* This routine changes the nesting level of an object and all of */
1313 /* its subobjects so they fit in with their place in the overall */
1314 /* ODL tree. This is particularly useful when objects are cut */
1315 /* from one tree and pasted into another tree, perhaps higher or */
1316 /* lower in the nesting hierarchy then they were in the original */
1317 /* tree. */
1318 /* */
1319 /************************************************************************/
1320 
1321 #ifdef _NO_PROTO
1322 
1323 void OdlAdjustObjDescLevel (object)
1324 
1325 OBJDESC *object;
1326 
1327 #else
1328 
1329 void OdlAdjustObjDescLevel (OBJDESC *object)
1330 
1331 #endif
1332 {
1333  OBJDESC *obj = {NULL};
1334  unsigned short scope = {ODL_RECURSIVE_DOWN};
1335 
1336  for (obj=object; obj != NULL;
1337  obj = (OBJDESC *) OdlNextObjDesc(obj, object->level, &scope))
1338  {
1339  obj->level = (obj->parent == NULL) ? 0 : (1 + obj->parent->level);
1340  }
1341 
1342  return;
1343 
1344 } /* End routine: "OdlAdjustObjDescLevel" */
1345 
1346 
1347 
1348 /************************************************************************/
1349 /* */
1350 /* Component: */
1351 /* */
1352 /* OdlGetObjDescParent */
1353 /* */
1354 /* Author: */
1355 /* */
1356 /* David P. Bernath (Jet Propulsion Laboratory) */
1357 /* */
1358 /* Version: */
1359 /* */
1360 /* 1.0 March 31, 1994 */
1361 /* */
1362 /* Change History: */
1363 /* */
1364 /* 03-31-94 Original code */
1365 /* */
1366 /*----------------------------------------------------------------------*/
1367 /* */
1368 /* Description: */
1369 /* */
1370 /* This routine returns a pointer to an object's parent. */
1371 /* */
1372 /* WARNING: NO MEMORY IS ALLOCATED BY THIS ROUTINE. THE RETURN */
1373 /* VALUE IS A POINTER TO AN EXISTING ODL OBJECT AND */
1374 /* AND MUST NOT BE FREED. */
1375 /* */
1376 /************************************************************************/
1377 
1378 #ifdef _NO_PROTO
1379 
1380 OBJDESC *OdlGetObjDescParent (object)
1381 
1382 OBJDESC *object;
1383 
1384 #else
1385 
1386 OBJDESC *OdlGetObjDescParent (OBJDESC *object)
1387 
1388 #endif
1389 {
1390  OBJDESC *parent = {NULL};
1391 
1392  if (object != NULL)
1393  parent = object->parent;
1394 
1395  return(parent);
1396 
1397 } /* End: "OdlGetObjDescParent" */
1398 
1399 
1400 
1401 
1402 /*========================================================================*/
1403 /* */
1404 /* Keyword routines */
1405 /* */
1406 /*========================================================================*/
1407 
1408 
1409 /************************************************************************/
1410 /* */
1411 /* Component: */
1412 /* */
1413 /* OdlFindKwd */
1414 /* */
1415 /* Author: */
1416 /* */
1417 /* David P. Bernath (Jet Propulsion Laboratory) */
1418 /* */
1419 /* Version: */
1420 /* */
1421 /* 1.0 March 31, 1994 */
1422 /* */
1423 /* Change History: */
1424 /* */
1425 /* 03-31-94 Original code */
1426 /* */
1427 /*----------------------------------------------------------------------*/
1428 /* */
1429 /* Description: */
1430 /* */
1431 /* This routine locates the keyword in a label that satisfies the */
1432 /* requirements passed in: The object where the search is to */
1433 /* begin, the name of the keyword, a particular value that the */
1434 /* keyword must have, which version of the keyword we want (if */
1435 /* there are duplicates), and the search scope we want to use to */
1436 /* limit the objects searched. */
1437 /* */
1438 /************************************************************************/
1439 
1440 #ifdef _NO_PROTO
1441 
1442 KEYWORD *OdlFindKwd (start_object, keyword_name, keyword_value,
1443  keyword_position, search_scope)
1444 OBJDESC *start_object;
1445 const char *keyword_name;
1446 char *keyword_value;
1447 unsigned long keyword_position;
1448 unsigned short search_scope;
1449 
1450 #else
1451 
1452 KEYWORD *OdlFindKwd (OBJDESC *start_object, const char *keyword_name,
1453  char *keyword_value, unsigned long keyword_position,
1454  unsigned short search_scope)
1455 
1456 #endif
1457 {
1458  OBJDESC *obj = {NULL};
1459  KEYWORD *kwd = {NULL};
1460  KEYWORD *found_kwd = {NULL};
1461  unsigned short found = {FALSE};
1462  unsigned short scope = {search_scope};
1463  unsigned long current_position = {0};
1464 
1465  for (obj=start_object;
1466  ((obj != NULL) && (! found));
1467  obj = (OBJDESC *) OdlNextObjDesc(obj, start_object->level, &scope))
1468  {
1469  for (kwd=obj->first_keyword; ((kwd != NULL) && (! found)); kwd=kwd->right_sibling)
1470  {
1471  if (keyword_name == NULL)
1472  found = TRUE;
1473  else
1474  found = OdlWildCardCompare(keyword_name, kwd->name);
1475 
1476  if ((found) && (keyword_value != NULL))
1477  found = OdlWildCardCompare(keyword_value, (char *) OdlGetKwdValue(kwd));
1478 
1479  if ((found) && (keyword_position != 0))
1480  found = ((++current_position) == keyword_position);
1481 
1482  if (found) found_kwd = kwd;
1483 
1484  } /* End: "for (kwd=obj-> ..." */
1485 
1486  } /* End: "for (obj=start_object; ..." */
1487 
1488  return(found_kwd);
1489 
1490 } /* End: "OdlFindKwd" */
1491 
1492 
1493 
1494 /************************************************************************/
1495 /* */
1496 /* Component: */
1497 /* */
1498 /* OdlNextKwd */
1499 /* */
1500 /* Author: */
1501 /* */
1502 /* David P. Bernath (Jet Propulsion Laboratory) */
1503 /* */
1504 /* Version: */
1505 /* */
1506 /* 1.0 March 31, 1994 */
1507 /* */
1508 /* Change History: */
1509 /* */
1510 /* 03-31-94 Original code */
1511 /* */
1512 /*----------------------------------------------------------------------*/
1513 /* */
1514 /* Description: */
1515 /* */
1516 /* This routine locates the keyword in a label that satisfies the */
1517 /* requirements passed in: The object where the search is to */
1518 /* begin, the name of the keyword, a particular value that the */
1519 /* keyword must have, which version of the keyword we want (if */
1520 /* there are duplicates), and the search scope we want to use to */
1521 /* limit the objects searched. */
1522 /* */
1523 /************************************************************************/
1524 
1525 #ifdef _NO_PROTO
1526 
1527 KEYWORD *OdlNextKwd (start_keyword, keyword_name, keyword_value,
1528  keyword_position, search_scope)
1529 
1530 KEYWORD *start_keyword;
1531 char *keyword_name;
1532 char *keyword_value;
1533 unsigned long keyword_position;
1534 unsigned short search_scope;
1535 
1536 #else
1537 
1538 KEYWORD *OdlNextKwd (KEYWORD *start_keyword, char *keyword_name,
1539  char *keyword_value, unsigned long keyword_position,
1540  unsigned short search_scope)
1541 
1542 #endif
1543 {
1544  OBJDESC *start_object = {NULL};
1545  OBJDESC *obj = {NULL};
1546  KEYWORD *kwd = {NULL};
1547  KEYWORD *found_kwd = {NULL};
1548  unsigned short found = {FALSE};
1549  unsigned short scope = {search_scope};
1550  unsigned long current_position = {0};
1551 
1552  if (start_keyword != NULL)
1553  {
1554  start_object = start_keyword->parent;
1555  obj = start_object;
1556  kwd = start_keyword;
1557 
1558  do
1559  {
1560  for ( ; ((kwd != NULL) && (! found)); kwd=kwd->right_sibling)
1561  {
1562  if (keyword_name == NULL)
1563  found = TRUE;
1564  else
1565  found = OdlWildCardCompare(keyword_name, kwd->name);
1566 
1567  if ((found) && (keyword_value != NULL))
1568  found = OdlWildCardCompare(keyword_value, (char *) OdlGetKwdValue(kwd));
1569 
1570  if ((found) && (keyword_position != 0))
1571  found = ((++current_position) == keyword_position);
1572 
1573  if (found) found_kwd = kwd;
1574 
1575  } /* End: "for (kwd=start_keyword; ..." */
1576 
1577  if (! found)
1578  {
1579  obj = (OBJDESC *) OdlNextObjDesc(obj, start_object->level, &scope);
1580  kwd = (KEYWORD *) OdlGetFirstKwd(obj);
1581  }
1582 
1583  } while ((obj != NULL) && (! found));
1584 
1585  } /* End: "if (start_keyword != NULL) ..." */
1586 
1587  return(found_kwd);
1588 
1589 } /* End: "OdlNextKwd" */
1590 
1591 
1592 
1593 /************************************************************************/
1594 /* */
1595 /* Component: */
1596 /* */
1597 /* OdlCutKwd */
1598 /* */
1599 /* Author: */
1600 /* */
1601 /* David P. Bernath (Jet Propulsion Laboratory) */
1602 /* */
1603 /* Version: */
1604 /* */
1605 /* 1.0 March 31, 1994 */
1606 /* */
1607 /* Change History: */
1608 /* */
1609 /* 03-31-94 Original code */
1610 /* */
1611 /*----------------------------------------------------------------------*/
1612 /* */
1613 /* Description: */
1614 /* */
1615 /* This routine removes a keyword from an object and returns a */
1616 /* pointer to it. All references to the object within the keyword */
1617 /* are removed, and all references to the keyword within the */
1618 /* object are removed. */
1619 /* */
1620 /* WARNING: NO MEMORY IS ALLOCATED BY THIS ROUTINE. THE RETURN */
1621 /* VALUE IS A POINTER TO AN EXISTING KEYWORD STRUCTURE */
1622 /* AND MUST NOT BE FREED. */
1623 /* */
1624 /************************************************************************/
1625 
1626 #ifdef _NO_PROTO
1627 
1628 KEYWORD *OdlCutKwd (keyword)
1629 
1630 KEYWORD *keyword;
1631 
1632 #else
1633 
1634 KEYWORD *OdlCutKwd (KEYWORD *keyword)
1635 
1636 #endif
1637 {
1638  if (keyword != NULL)
1639  {
1640  if (keyword->left_sibling != NULL)
1641  keyword->left_sibling->right_sibling = keyword->right_sibling;
1642 
1643  if (keyword->right_sibling != NULL)
1644  keyword->right_sibling->left_sibling = keyword->left_sibling;
1645 
1646  if (keyword->parent->first_keyword == keyword)
1647  keyword->parent->first_keyword = keyword->right_sibling;
1648 
1649  if (keyword->parent->last_keyword == keyword)
1650  keyword->parent->last_keyword = keyword->left_sibling;
1651 
1652  keyword->parent = NULL;
1653  keyword->left_sibling = NULL;
1654  keyword->right_sibling = NULL;
1655 
1656  } /* End: "if ((keyword != NULL) && ..." */
1657 
1658  return(keyword);
1659 
1660 } /* End routine: "OdlCutKwd" */
1661 
1662 
1663 /************************************************************************/
1664 /* */
1665 /* Component: */
1666 /* */
1667 /* OdlPasteKwd */
1668 /* */
1669 /* Author: */
1670 /* */
1671 /* David P. Bernath (Jet Propulsion Laboratory) */
1672 /* */
1673 /* Version: */
1674 /* */
1675 /* 1.0 March 31, 1994 */
1676 /* */
1677 /* Change History: */
1678 /* */
1679 /* 03-31-94 Original code */
1680 /* */
1681 /*----------------------------------------------------------------------*/
1682 /* */
1683 /* Description: */
1684 /* */
1685 /* This routine adds a keyword to the end of an object's keyword */
1686 /* list. */
1687 /* */
1688 /************************************************************************/
1689 
1690 #ifdef _NO_PROTO
1691 
1692 KEYWORD *OdlPasteKwd (keyword, object)
1693 
1694 KEYWORD *keyword;
1695 OBJDESC *object;
1696 
1697 #else
1698 
1699 KEYWORD *OdlPasteKwd (KEYWORD *keyword, OBJDESC *object)
1700 
1701 #endif
1702 {
1703  if ((keyword != NULL) && (object != NULL))
1704  {
1705  keyword->parent = object;
1706  keyword->left_sibling = object->last_keyword;
1707  keyword->right_sibling = NULL;
1708 
1709  if (object->first_keyword == NULL)
1710  object->first_keyword = keyword;
1711 
1712  if (object->last_keyword != NULL)
1713  object->last_keyword->right_sibling = keyword;
1714 
1715  object->last_keyword = keyword;
1716 
1717  } /* End: "if ((keyword != NULL) && ..." */
1718 
1719  return(keyword);
1720 
1721 } /* End routine: "OdlPasteKwd" */
1722 
1723 
1724 /************************************************************************/
1725 /* */
1726 /* Component: */
1727 /* */
1728 /* OdlPasteKwdBefore */
1729 /* */
1730 /* Author: */
1731 /* */
1732 /* David P. Bernath (Jet Propulsion Laboratory) */
1733 /* */
1734 /* Version: */
1735 /* */
1736 /* 1.0 March 31, 1994 */
1737 /* */
1738 /* Change History: */
1739 /* */
1740 /* 03-31-94 Original code */
1741 /* */
1742 /*----------------------------------------------------------------------*/
1743 /* */
1744 /* Description: */
1745 /* */
1746 /* This routine adds a keyword to an object as the left sibling of */
1747 /* the old_keyword. */
1748 /* */
1749 /************************************************************************/
1750 
1751 #ifdef _NO_PROTO
1752 
1753 KEYWORD *OdlPasteKwdBefore (new_keyword, old_keyword)
1754 
1755 KEYWORD *new_keyword;
1756 KEYWORD *old_keyword;
1757 
1758 #else
1759 
1760 KEYWORD *OdlPasteKwdBefore (KEYWORD *new_keyword, KEYWORD *old_keyword)
1761 
1762 #endif
1763 {
1764  if ((new_keyword != NULL) && (old_keyword != NULL))
1765  {
1766  new_keyword->parent = old_keyword->parent;
1767  new_keyword->left_sibling = old_keyword->left_sibling;
1768  new_keyword->right_sibling = old_keyword;
1769 
1770  if (old_keyword->left_sibling == NULL)
1771  old_keyword->parent->first_keyword = new_keyword;
1772  else
1773  old_keyword->left_sibling->right_sibling = new_keyword;
1774 
1775  old_keyword->left_sibling = new_keyword;
1776 
1777  } /* End: "if ((new_keyword != NULL) && ..." */
1778 
1779  return(new_keyword);
1780 
1781 } /* End routine: "OdlPasteKwdBefore" */
1782 
1783 
1784 /************************************************************************/
1785 /* */
1786 /* Component: */
1787 /* */
1788 /* OdlPasteKwdAfter */
1789 /* */
1790 /* Author: */
1791 /* */
1792 /* David P. Bernath (Jet Propulsion Laboratory) */
1793 /* */
1794 /* Version: */
1795 /* */
1796 /* 1.0 March 31, 1994 */
1797 /* */
1798 /* Change History: */
1799 /* */
1800 /* 03-31-94 Original code */
1801 /* */
1802 /*----------------------------------------------------------------------*/
1803 /* */
1804 /* Description: */
1805 /* */
1806 /* This routine adds a keyword to an object as the right sibling */
1807 /* of the old_keyword. */
1808 /* */
1809 /************************************************************************/
1810 
1811 #ifdef _NO_PROTO
1812 
1813 KEYWORD *OdlPasteKwdAfter (new_keyword, old_keyword)
1814 
1815 KEYWORD *new_keyword;
1816 KEYWORD *old_keyword;
1817 
1818 #else
1819 
1820 KEYWORD *OdlPasteKwdAfter (KEYWORD *new_keyword, KEYWORD *old_keyword)
1821 
1822 #endif
1823 {
1824  if ((new_keyword != NULL) && (old_keyword != NULL))
1825  {
1826  new_keyword->parent = old_keyword->parent;
1827  new_keyword->right_sibling = old_keyword->right_sibling;
1828  new_keyword->left_sibling = old_keyword;
1829 
1830  if (old_keyword->right_sibling == NULL)
1831  old_keyword->parent->last_keyword = new_keyword;
1832  else
1833  old_keyword->right_sibling->left_sibling = new_keyword;
1834 
1835  old_keyword->right_sibling = new_keyword;
1836 
1837  } /* End: "if ((new_keyword != NULL) && ..." */
1838 
1839  return(new_keyword);
1840 
1841 } /* End routine: "OdlPasteKwdAfter" */
1842 
1843 
1844 /************************************************************************/
1845 /* */
1846 /* Component: */
1847 /* */
1848 /* OdlCopyKwd */
1849 /* */
1850 /* Author: */
1851 /* */
1852 /* David P. Bernath (Jet Propulsion Laboratory) */
1853 /* */
1854 /* Version: */
1855 /* */
1856 /* 1.0 March 31, 1994 */
1857 /* */
1858 /* Change History: */
1859 /* */
1860 /* 03-31-94 Original code */
1861 /* */
1862 /*----------------------------------------------------------------------*/
1863 /* */
1864 /* Description: */
1865 /* */
1866 /* This routine makes a copy of a keyword and returns a pointer to */
1867 /* it. All of the keyword's fields are duplicated except for */
1868 /* references to the parent object, which are removed. */
1869 /* */
1870 /************************************************************************/
1871 
1872 #ifdef _NO_PROTO
1873 
1874 KEYWORD *OdlCopyKwd (keyword)
1875 
1876 KEYWORD *keyword;
1877 
1878 #else
1879 
1880 KEYWORD *OdlCopyKwd (KEYWORD *keyword)
1881 
1882 #endif
1883 {
1884  KEYWORD *new_keyword = {NULL};
1885 
1886  if (keyword != NULL)
1887  {
1888  new_keyword = OdlNewKwd(keyword->name, keyword->value,
1889  keyword->pre_comment, keyword->line_comment,
1890  keyword->file_name, (long)keyword->line_number);
1891  }
1892 
1893  return(new_keyword);
1894 
1895 } /* End routine: "OdlCopyKwd" */
1896 
1897 
1898 /************************************************************************/
1899 /* */
1900 /* Component: */
1901 /* */
1902 /* OdlNewKwd */
1903 /* */
1904 /* Author: */
1905 /* */
1906 /* David P. Bernath (Jet Propulsion Laboratory) */
1907 /* */
1908 /* Version: */
1909 /* */
1910 /* 1.0 March 31, 1994 */
1911 /* */
1912 /* Change History: */
1913 /* */
1914 /* 03-31-94 Original code */
1915 /* */
1916 /*----------------------------------------------------------------------*/
1917 /* */
1918 /* Description: */
1919 /* */
1920 /* This routine creates a new keyword structure, initializes */
1921 /* its fields with the values passed in, and returns a pointer */
1922 /* to it. */
1923 /* */
1924 /************************************************************************/
1925 
1926 #ifdef _NO_PROTO
1927 
1928 KEYWORD *OdlNewKwd (keyword_name, value_text, pre_comment,
1929  line_comment, file_name, line_number)
1930 
1931 char *keyword_name;
1932 char *value_text;
1933 char *pre_comment;
1934 char *line_comment;
1935 char *file_name;
1936 long line_number;
1937 
1938 #else
1939 
1940 KEYWORD *OdlNewKwd (char *keyword_name, char *value_text, char *pre_comment,
1941  char *line_comment, char *file_name, long line_number)
1942 
1943 #endif
1944 {
1945  KEYWORD *new_keyword = {NULL};
1946 
1947  if ((new_keyword = (KEYWORD *)malloc(sizeof(KEYWORD))) == NULL)
1948  SayGoodbye()
1949  else
1950  {
1951  CopyString(new_keyword->name, keyword_name)
1952  CopyString(new_keyword->pre_comment, pre_comment)
1953  CopyString(new_keyword->line_comment, line_comment)
1954  CopyString(new_keyword->file_name, file_name)
1955  CopyString(new_keyword->value, value_text)
1956 
1957  new_keyword->is_a_pointer = (keyword_name == NULL) ? FALSE : (*keyword_name == '^');
1958 
1959  if (value_text == NULL)
1960  {
1961  new_keyword->size = 0;
1962  new_keyword->is_a_list = FALSE;
1963  }
1964  else
1965  {
1966  new_keyword->size = strlen(new_keyword->value);
1967  new_keyword->is_a_list = ((*value_text == '{') || (*value_text == '('));
1968  }
1969 
1970  new_keyword->line_number = line_number;
1971  new_keyword->parent = NULL;
1972  new_keyword->left_sibling = NULL;
1973  new_keyword->right_sibling = NULL;
1974  new_keyword->appl1 = NULL;
1975  new_keyword->appl2 = NULL;
1976 
1977  } /* End: "if ((new_keyword = ... else ..." */
1978 
1979  return(new_keyword);
1980 
1981 } /* End routine: "OdlNewKwd" */
1982 
1983 
1984 
1985 /************************************************************************/
1986 /* */
1987 /* Component: */
1988 /* */
1989 /* OdlGetFirstKwd */
1990 /* */
1991 /* Author: */
1992 /* */
1993 /* David P. Bernath (Jet Propulsion Laboratory) */
1994 /* */
1995 /* Version: */
1996 /* */
1997 /* 1.0 March 31, 1994 */
1998 /* */
1999 /* Change History: */
2000 /* */
2001 /* 03-31-94 Original code */
2002 /* */
2003 /*----------------------------------------------------------------------*/
2004 /* */
2005 /* Description: */
2006 /* */
2007 /* This routine returns a pointer to the first keyword data */
2008 /* structure in an object definition structure. */
2009 /* */
2010 /* WARNING: NO MEMORY IS ALLOCATED BY THIS ROUTINE. THE RETURN */
2011 /* VALUE IS A POINTER TO THE ACTUAL INFORMATION STORED */
2012 /* IN THE OBJECT DATA STRUCTURE AND MUST NOT BE FREED. */
2013 /* */
2014 /************************************************************************/
2015 
2016 #ifdef _NO_PROTO
2017 
2018 KEYWORD *OdlGetFirstKwd (object)
2019 
2020 OBJDESC *object;
2021 
2022 #else
2023 
2024 KEYWORD *OdlGetFirstKwd (OBJDESC *object)
2025 
2026 #endif
2027 {
2028  KEYWORD *kwd = {NULL};
2029 
2030  if (object != NULL)
2031  kwd = object->first_keyword;
2032 
2033  return(kwd);
2034 
2035 } /* End: "OdlGetFirstKwd" */
2036 
2037 
2038 
2039 /************************************************************************/
2040 /* */
2041 /* Component: */
2042 /* */
2043 /* OdlGetNextKwd */
2044 /* */
2045 /* Author: */
2046 /* */
2047 /* David P. Bernath (Jet Propulsion Laboratory) */
2048 /* */
2049 /* Version: */
2050 /* */
2051 /* 1.0 March 31, 1994 */
2052 /* */
2053 /* Change History: */
2054 /* */
2055 /* 03-31-94 Original code */
2056 /* */
2057 /*----------------------------------------------------------------------*/
2058 /* */
2059 /* Description: */
2060 /* */
2061 /* This routine returns a pointer to the next keyword data */
2062 /* structure in an object definition's list of keyword structures. */
2063 /* */
2064 /* WARNING: NO MEMORY IS ALLOCATED BY THIS ROUTINE. THE RETURN */
2065 /* VALUE IS A POINTER TO THE ACTUAL INFORMATION STORED */
2066 /* IN THE OBJECT DATA STRUCTURE AND MUST NOT BE FREED. */
2067 /* */
2068 /************************************************************************/
2069 
2070 #ifdef _NO_PROTO
2071 
2072 KEYWORD *OdlGetNextKwd (keyword)
2073 
2074 KEYWORD *keyword;
2075 
2076 #else
2077 
2078 KEYWORD *OdlGetNextKwd (KEYWORD *keyword)
2079 
2080 #endif
2081 {
2082  KEYWORD *kwd = {NULL};
2083 
2084  if (keyword != NULL)
2085  kwd = keyword->right_sibling;
2086 
2087  return(kwd);
2088 
2089 } /* End: "OdlGetNextKwd" */
2090 
2091 
2092 
2093 /************************************************************************/
2094 /* */
2095 /* Component: */
2096 /* */
2097 /* OdlGetKwdValue */
2098 /* */
2099 /* Author: */
2100 /* */
2101 /* David P. Bernath (Jet Propulsion Laboratory) */
2102 /* */
2103 /* Version: */
2104 /* */
2105 /* 1.0 March 31, 1994 */
2106 /* */
2107 /* Change History: */
2108 /* */
2109 /* 03-31-94 Original code */
2110 /* */
2111 /*----------------------------------------------------------------------*/
2112 /* */
2113 /* Description: */
2114 /* */
2115 /* This routine returns a pointer to a keyword's value. */
2116 /* */
2117 /* WARNING: NO MEMORY IS ALLOCATED BY THIS ROUTINE. THE RETURN */
2118 /* VALUE IS A POINTER TO THE ACTUAL INFORMATION STORED */
2119 /* IN THE KEYWORD DATA STRUCTURE AND MUST NOT BE FREED. */
2120 /* */
2121 /************************************************************************/
2122 
2123 #ifdef _NO_PROTO
2124 
2125 char *OdlGetKwdValue (keyword)
2126 
2127 KEYWORD *keyword;
2128 
2129 #else
2130 
2131 char *OdlGetKwdValue (KEYWORD *keyword)
2132 
2133 #endif
2134 {
2135  char *value = {NULL};
2136 
2137  if (keyword != NULL)
2138  value = keyword->value;
2139 
2140  return(value);
2141 
2142 } /* End: "OdlGetKwdValue" */
2143 
2144 
2145 
2146 /************************************************************************/
2147 /* */
2148 /* Component: */
2149 /* */
2150 /* OdlGetAllKwdValues */
2151 /* */
2152 /* Author: */
2153 /* */
2154 /* David P. Bernath (Jet Propulsion Laboratory) */
2155 /* */
2156 /* Version: */
2157 /* */
2158 /* 1.0 March 31, 1994 */
2159 /* */
2160 /* Change History: */
2161 /* */
2162 /* 03-31-94 Original code */
2163 /* */
2164 /*----------------------------------------------------------------------*/
2165 /* */
2166 /* Description: */
2167 /* */
2168 /* This routine extracts each individual value from a set or */
2169 /* sequence of values of a keyword, stores these values in a */
2170 /* linked list, and returns a pointer to this list. */
2171 /* */
2172 /* For example, if a keyword has this combination of sets and */
2173 /* sequences as its value: */
2174 /* */
2175 /* {red, (green, blue), {17, (("book.lbl", 345), orange)}} */
2176 /* */
2177 /* Then the TB_STRING_LIST returned would contain: */
2178 /* */
2179 /* red */
2180 /* green */
2181 /* blue */
2182 /* 17 */
2183 /* "book.lbl" */
2184 /* 345 */
2185 /* orange */
2186 /* */
2187 /* WARNING: The string list must be freed using the */
2188 /* RemoveStringList macro (look in toolbox.h). */
2189 /* */
2190 /************************************************************************/
2191 
2192 #ifdef _NO_PROTO
2193 
2194 TB_STRING_LIST *OdlGetAllKwdValues (keyword)
2195 
2196 KEYWORD *keyword;
2197 
2198 #else
2199 
2200 TB_STRING_LIST *OdlGetAllKwdValues (KEYWORD *keyword)
2201 
2202 #endif
2203 {
2204  TB_STRING_LIST *value_list = {NULL};
2205  char *val_start = {NULL};
2206  char *val_stop = {NULL};
2207  char save_ch;
2208 
2209  if (keyword != NULL)
2210  {
2211  if (keyword->value != NULL)
2212  {
2213  for (val_start=(char *)OdlValueStart(keyword->value);
2214  *val_start != '\0';
2215  val_start=(char *)OdlValueStart(val_stop+1))
2216  {
2217  val_stop = (char *) OdlValueEnd(val_start);
2218  save_ch = *(val_stop + 1); *(val_stop + 1) = '\0';
2219  AddStringToList(val_start, value_list)
2220  *(val_stop + 1) = save_ch;
2221  }
2222 
2223  } /* End: "if (keyword->value != NULL) ..." */
2224 
2225  } /* End: "if (keyword != NULL) ..." */
2226 
2227  return(value_list);
2228 
2229 } /* End: "OdlGetAllKwdValues" */
2230 
2231 
2232 
2233 /************************************************************************/
2234 /* */
2235 /* Component: */
2236 /* */
2237 /* OdlGetKwdValueType */
2238 /* */
2239 /* Author: */
2240 /* */
2241 /* David P. Bernath (Jet Propulsion Laboratory) */
2242 /* */
2243 /* Version: */
2244 /* */
2245 /* 1.0 March 31, 1994 */
2246 /* */
2247 /* Change History: */
2248 /* */
2249 /* 03-31-94 Original code */
2250 /* */
2251 /*----------------------------------------------------------------------*/
2252 /* */
2253 /* Description: */
2254 /* */
2255 /* This routine determines the data type of a keyword's value and */
2256 /* returns a data type symbolic id. Possible symbolic ids are: */
2257 /* */
2258 /* ODL_UNKNOWN (can't tell what the heck it is) */
2259 /* ODL_INTEGER (handles optional leading plus or minus) */
2260 /* ODL_REAL (handles optional leading plus or minus, */
2261 /* scientific notation, and real exponents) */
2262 /* ODL_SYMBOL (unqouted or single quoted string of */
2263 /* characters) */
2264 /* ODL_TEXT (double quoted string of characters) */
2265 /* ODL_DATE (yyyy-mm-dd or yyyy-ddd) */
2266 /* ODL_DATE_TIME (yyyy-mm-ddThh:mm:ss.h) */
2267 /* ODL_SEQUENCE (starts with a paren character "{") */
2268 /* ODL_SET (starts with a brace character "(") */
2269 /* */
2270 /************************************************************************/
2271 
2272 #ifdef _NO_PROTO
2273 
2274 unsigned short OdlGetKwdValueType (keyword)
2275 
2276 KEYWORD *keyword;
2277 
2278 #else
2279 
2280 unsigned short OdlGetKwdValueType (KEYWORD *keyword)
2281 
2282 #endif
2283 {
2284  unsigned short type = {ODL_UNKNOWN};
2285  if (keyword != NULL) type = (unsigned short) OdlDataType(keyword->value);
2286  return(type);
2287 
2288 } /* End: "OdlGetKwdValueType" */
2289 
2290 
2291 
2292 /************************************************************************/
2293 /* */
2294 /* Component: */
2295 /* */
2296 /* OdlGetKwdUnit */
2297 /* */
2298 /* Author: */
2299 /* */
2300 /* David P. Bernath (Jet Propulsion Laboratory) */
2301 /* */
2302 /* Version: */
2303 /* */
2304 /* 1.0 March 31, 1994 */
2305 /* */
2306 /* Change History: */
2307 /* */
2308 /* 03-31-94 Original code */
2309 /* */
2310 /*----------------------------------------------------------------------*/
2311 /* */
2312 /* Description: */
2313 /* */
2314 /* This routine locates the units part of a keyword's value, */
2315 /* extracts it, stores it in a new character string, and returns */
2316 /* a pointer to this new character string. */
2317 /* */
2318 /* WARNING: This routine allocates memory for the return value */
2319 /* that must be freed. */
2320 /* */
2321 /************************************************************************/
2322 
2323 #ifdef _NO_PROTO
2324 
2325 char *OdlGetKwdUnit (keyword)
2326 
2327 KEYWORD *keyword;
2328 
2329 #else
2330 
2331 char *OdlGetKwdUnit (KEYWORD *keyword)
2332 
2333 #endif
2334 {
2335  char *c = {NULL};
2336  char *unit = {NULL};
2337 
2338  /* If we were given a keyword to use */
2339  if (keyword != NULL)
2340  {
2341  /* Attempt to locate the units string */
2342  c = (char *) strchr(keyword->value, '<');
2343 
2344  if (c != NULL)
2345  {
2346  /* We found it! Now copy it and make it upper case */
2347  CopyString(unit, c)
2348  UpperCase(unit)
2349 
2350  /* Close off the units string */
2351  c = (char *) strchr(unit, '>');
2352  if (c != NULL) *(c + 1) = '\0';
2353  }
2354 
2355  } /* End: "if (keyword != NULL) ..." */
2356 
2357  return(unit);
2358 
2359 } /* End: "OdlGetKwdUnit" */
2360 
2361 
2362 
2363 /************************************************************************/
2364 /* */
2365 /* Component: */
2366 /* */
2367 /* OdlGetKwdName */
2368 /* */
2369 /* Author: */
2370 /* */
2371 /* David P. Bernath (Jet Propulsion Laboratory) */
2372 /* */
2373 /* Version: */
2374 /* */
2375 /* 1.0 March 31, 1994 */
2376 /* */
2377 /* Change History: */
2378 /* */
2379 /* 03-31-94 Original code */
2380 /* */
2381 /*----------------------------------------------------------------------*/
2382 /* */
2383 /* Description: */
2384 /* */
2385 /* This routine returns the name of a keyword. */
2386 /* */
2387 /* WARNING: NO MEMORY IS ALLOCATED BY THIS ROUTINE. THE RETURN */
2388 /* VALUE IS A POINTER TO THE ACTUAL INFORMATION STORED */
2389 /* IN THE KEYWORD DATA STRUCTURE AND MUST NOT BE FREED. */
2390 /* */
2391 /************************************************************************/
2392 
2393 #ifdef _NO_PROTO
2394 
2395 char *OdlGetKwdName (keyword)
2396 
2397 KEYWORD *keyword;
2398 
2399 #else
2400 
2401 char *OdlGetKwdName (KEYWORD *keyword)
2402 
2403 #endif
2404 {
2405  char *name = {NULL};
2406 
2407  if (keyword != NULL)
2408  name = keyword->name;
2409 
2410  return(name);
2411 
2412 } /* End: "OdlGetKwdName" */
2413 
2414 
2415 
2416 
2417 
2418 /*========================================================================*/
2419 /* */
2420 /* Memory deallocation routines */
2421 /* */
2422 /*========================================================================*/
2423 
2424 /************************************************************************/
2425 /* */
2426 /* Component: */
2427 /* */
2428 /* OdlFreeTree */
2429 /* */
2430 /* Author: */
2431 /* */
2432 /* David P. Bernath (Jet Propulsion Laboratory) */
2433 /* */
2434 /* Version: */
2435 /* */
2436 /* 1.0 March 31, 1994 */
2437 /* */
2438 /* Change History: */
2439 /* */
2440 /* 03-31-94 Original code */
2441 /* */
2442 /*----------------------------------------------------------------------*/
2443 /* */
2444 /* Description: */
2445 /* */
2446 /* This routine frees all memory used by an ODL tree. The return */
2447 /* value is always NULL. */
2448 /* */
2449 /************************************************************************/
2450 
2451 #ifdef _NO_PROTO
2452 
2453 OBJDESC *OdlFreeTree (object)
2454 
2455 OBJDESC *object;
2456 
2457 #else
2458 
2459 OBJDESC *OdlFreeTree (OBJDESC *object)
2460 
2461 #endif
2462 {
2463  if (object != NULL)
2464  {
2465  (void)OdlFreeTree(object->first_child);
2466  (void)OdlFreeTree(object->right_sibling);
2467  (void)OdlFreeAllKwds(object);
2468  LemmeGo(object->class)
2469  LemmeGo(object->pre_comment)
2470  LemmeGo(object->line_comment)
2471  LemmeGo(object->post_comment)
2472  LemmeGo(object->end_comment)
2473  LemmeGo(object->file_name)
2474  LemmeGo(object)
2475  }
2476 
2477  return(object);
2478 
2479 } /* End: "OdlFreeTree" */
2480 
2481 
2482 
2483 
2484 /************************************************************************/
2485 /* */
2486 /* Component: */
2487 /* */
2488 /* OdlFreeAllKwds */
2489 /* */
2490 /* Author: */
2491 /* */
2492 /* David P. Bernath (Jet Propulsion Laboratory) */
2493 /* */
2494 /* Version: */
2495 /* */
2496 /* 1.0 March 31, 1994 */
2497 /* */
2498 /* Change History: */
2499 /* */
2500 /* 03-31-94 Original code */
2501 /* */
2502 /*----------------------------------------------------------------------*/
2503 /* */
2504 /* Description: */
2505 /* */
2506 /* This routine frees all memory used by an object's keywords. */
2507 /* When it's finished, all references to keywords are gone from */
2508 /* the object. The return value is always NULL. */
2509 /* */
2510 /************************************************************************/
2511 
2512 #ifdef _NO_PROTO
2513 
2514 KEYWORD *OdlFreeAllKwds (object)
2515 
2516 OBJDESC *object;
2517 
2518 #else
2519 
2520 KEYWORD *OdlFreeAllKwds (OBJDESC *object)
2521 
2522 #endif
2523 {
2524  KEYWORD *kwd = {NULL};
2525 
2526  if (object != NULL)
2527  {
2528  for (kwd=object->first_keyword; kwd != NULL;
2529  kwd=(KEYWORD *) OdlFreeKwd(kwd)) ;
2530 
2531  object->first_keyword = NULL;
2532  object->last_keyword = NULL;
2533  }
2534 
2535  return(kwd);
2536 
2537 } /* End: "OdlFreeAllKwds" */
2538 
2539 
2540 
2541 
2542 
2543 /************************************************************************/
2544 /* */
2545 /* Component: */
2546 /* */
2547 /* OdlFreeKwd */
2548 /* */
2549 /* Author: */
2550 /* */
2551 /* David P. Bernath (Jet Propulsion Laboratory) */
2552 /* */
2553 /* Version: */
2554 /* */
2555 /* 1.0 March 31, 1994 */
2556 /* */
2557 /* Change History: */
2558 /* */
2559 /* 03-31-94 Original code */
2560 /* */
2561 /*----------------------------------------------------------------------*/
2562 /* */
2563 /* Description: */
2564 /* */
2565 /* This routine frees the memory used by a keyword. The return */
2566 /* value is always a pointer to the right sibling of the keyword. */
2567 /* */
2568 /************************************************************************/
2569 
2570 #ifdef _NO_PROTO
2571 
2572 KEYWORD *OdlFreeKwd (keyword)
2573 
2574 KEYWORD *keyword;
2575 
2576 #else
2577 
2578 KEYWORD *OdlFreeKwd (KEYWORD *keyword)
2579 
2580 #endif
2581 {
2582  KEYWORD *next_kwd = {NULL};
2583 
2584  if (keyword != NULL)
2585  {
2586  next_kwd = keyword->right_sibling;
2587  LemmeGo(keyword->name)
2588  LemmeGo(keyword->file_name)
2589  LemmeGo(keyword->value)
2590  LemmeGo(keyword->pre_comment)
2591  LemmeGo(keyword->line_comment)
2592  LemmeGo(keyword)
2593  }
2594 
2595  return(next_kwd);
2596 
2597 } /* End: "OdlFreeKwd" */
2598 
2599 
2600 
2601 
2602 /*========================================================================*/
2603 /* */
2604 /* File and File Name routines */
2605 /* */
2606 /*========================================================================*/
2607 
2608 /************************************************************************/
2609 /* */
2610 /* Component: */
2611 /* */
2612 /* OdlOpenMessageFile */
2613 /* */
2614 /* Author: */
2615 /* */
2616 /* David P. Bernath (Jet Propulsion Laboratory) */
2617 /* */
2618 /* Version: */
2619 /* */
2620 /* 1.0 March 31, 1994 */
2621 /* */
2622 /* Change History: */
2623 /* */
2624 /* 03-31-94 Original code */
2625 /* */
2626 /*----------------------------------------------------------------------*/
2627 /* */
2628 /* Description: */
2629 /* */
2630 /* This routine returns a pointer to an opened file based on */
2631 /* what is passed in. If message_fptr is not NULL, the we assume */
2632 /* that the file is already open and return message_fptr. If */
2633 /* message_fname is NULL, or we can't open message_fname, then */
2634 /* we return stdout. If message_fname can be opened, then we */
2635 /* return a pointer to the newly opened file. */
2636 /* */
2637 /************************************************************************/
2638 
2639 #ifdef _NO_PROTO
2640 
2641 FILE *OdlOpenMessageFile (message_fname, message_fptr)
2642 
2643 const char *message_fname;
2644 FILE *message_fptr;
2645 
2646 #else
2647 
2648 FILE *OdlOpenMessageFile (const char *message_fname, FILE *message_fptr)
2649 
2650 #endif
2651 {
2652  FILE *fptr = {stdout};
2653 
2654  if (message_fptr != NULL)
2655  fptr = message_fptr;
2656  else
2657  if (message_fname != NULL && ! odl_suppress_messages)
2658  {
2659  if ((fptr = (FILE *) fopen(message_fname, "a")) == NULL)
2660  {
2661  fptr = stdout;
2662  (void)OdlPrintMessage(NULL, NULL, 0,
2663  "Unable to open the output file. Messages will be written to the terminal");
2664  }
2665  }
2666 
2667  return(fptr);
2668 
2669 } /* End routine: "OdlOpenMessageFile" */
2670 
2671 
2672 
2673 /************************************************************************/
2674 /* */
2675 /* Component: */
2676 /* */
2677 /* OdlGetFileName */
2678 /* */
2679 /* Author: */
2680 /* */
2681 /* David P. Bernath (Jet Propulsion Laboratory) */
2682 /* */
2683 /* Version: */
2684 /* */
2685 /* 1.0 March 31, 1994 */
2686 /* */
2687 /* Change History: */
2688 /* */
2689 /* 03-31-94 Original code */
2690 /* */
2691 /*----------------------------------------------------------------------*/
2692 /* */
2693 /* Description: */
2694 /* */
2695 /* This routine extracts the file name from a "^" keyword, */
2696 /* allocates storage for it, and returns a pointer to this new */
2697 /* character string. It also returns information about where */
2698 /* the data actually begins in the file. */
2699 /* */
2700 /* For example, lets say we're looking at a label in a file */
2701 /* called test.lbl, and we want to get the file name assocated */
2702 /* the FNAME keyword. Here are the possible values this keyword */
2703 /* might have, and what information would be returned for each */
2704 /* possibility: */
2705 /* */
2706 /* ^FNAME = 17 */
2707 /* */
2708 /* file name : test.lbl (attached) */
2709 /* *start_location : 17 */
2710 /* *start_location type : ODL_RECORD_LOCATION */
2711 /* */
2712 /* ^FNAME = 29 <RECORD> */
2713 /* */
2714 /* file name : test.lbl (attached) */
2715 /* *start_location : 29 */
2716 /* *start_location type : ODL_RECORD_LOCATION */
2717 /* */
2718 /* ^FNAME = 197 <RECORDS> */
2719 /* */
2720 /* file name : test.lbl (attached) */
2721 /* *start_location : 197 */
2722 /* *start_location type : ODL_RECORD_LOCATION */
2723 /* */
2724 /* ^FNAME = 346 <BYTE> */
2725 /* */
2726 /* file name : test.lbl (attached) */
2727 /* *start_location : 346 */
2728 /* *start_location type : ODL_BYTE_LOCATION */
2729 /* */
2730 /* ^FNAME = 2189 <BYTES> */
2731 /* */
2732 /* file name : test.lbl (detached) */
2733 /* *start_location : 2189 */
2734 /* *start_location type : ODL_BYTE_LOCATION */
2735 /* */
2736 /* ^FNAME = "file_name.dat" */
2737 /* */
2738 /* file name : file_name.dat (detached) */
2739 /* *start_location : 1 */
2740 /* *start_location type : ODL_RECORD_LOCATION */
2741 /* */
2742 /* ^FNAME = ("file_name.dat", 17) */
2743 /* */
2744 /* file name : file_name.dat (detached) */
2745 /* *start_location : 17 */
2746 /* *start_location type : ODL_RECORD_LOCATION */
2747 /* */
2748 /* ^FNAME = ("file_name.dat", 29 <RECORD>) */
2749 /* */
2750 /* file name : file_name.dat (detached) */
2751 /* *start_location : 29 */
2752 /* *start_location type : ODL_RECORD_LOCATION */
2753 /* */
2754 /* ^FNAME = ("file_name.dat", 197 <RECORDS>) */
2755 /* */
2756 /* file name : file_name.dat (detached) */
2757 /* *start_location : 197 */
2758 /* *start_location type : ODL_RECORD_LOCATION */
2759 /* */
2760 /* ^FNAME = ("file_name.dat", 346 <BYTE>) */
2761 /* */
2762 /* file name : file_name.dat (detached) */
2763 /* *start_location : 346 */
2764 /* *start_location type : ODL_BYTE_LOCATION */
2765 /* */
2766 /* ^FNAME = ("file_name.dat", 2189 <BYTES>) */
2767 /* */
2768 /* file name : file_name.dat (detached) */
2769 /* *start_location : 2189 */
2770 /* *start_location type : ODL_BYTE_LOCATION */
2771 /* */
2772 /************************************************************************/
2773 
2774 #ifdef _NO_PROTO
2775 
2776 char *OdlGetFileName (keyword, start_location, start_location_type)
2777 
2778 KEYWORD *keyword;
2779 unsigned long *start_location;
2780 unsigned short *start_location_type;
2781 
2782 #else
2783 
2784 char *OdlGetFileName (KEYWORD *keyword, unsigned long *start_location,
2785  unsigned short *start_location_type)
2786 
2787 #endif
2788 {
2789  char *fname = {NULL};
2790  char *text = {NULL};
2791  char *unit = {NULL};
2792  char *first_word = {NULL};
2793  char *second_word = {NULL};
2794 
2795  if (keyword != NULL)
2796  {
2797  /* Make a copy of the keyword's value */
2798  CopyString(text, keyword->value)
2799 
2800  /* Get rid of parens, braces, and commas */
2801  ReplaceChar(text, '(', ' ')
2802  ReplaceChar(text, ')', ' ')
2803  ReplaceChar(text, '{', ' ')
2804  ReplaceChar(text, '}', ' ')
2805  ReplaceChar(text, ',', ' ')
2806 
2807  /* Locate the units string */
2808  unit = (char *) strchr(text, '<');
2809 
2810  /* Remove the units string if it's there */
2811  if (unit != NULL) *unit = '\0';
2812 
2813  /* Find the first word */
2814  first_word = (char *) OdlFirstWord(text);
2815 
2816  /* If the first word is quoted, then it's a file name */
2817  if ((*first_word == '"') || (*first_word == '\''))
2818  {
2819  /* Look for a second word */
2820  second_word = (char *) OdlNextWord(first_word);
2821 
2822  /* If we can't find one, then the location is record 1 */
2823  if (*second_word == '\0')
2824  *start_location = 1;
2825  else
2826  {
2827  /* Otherwise, the second word is the location */
2828  *start_location = atoi(second_word);
2829  *(second_word - 1) = '\0';
2830  }
2831 
2832  /* Copy and clean up the file name */
2833  CopyString(fname, (first_word+1))
2834  ReplaceChar(fname, '"', ' ');
2835  ReplaceChar(fname, '\'', ' ');
2836  StripTrailing(fname, ' ')
2837  }
2838  else
2839  {
2840  /* Since the first word isn't quoted, we assume that it's a */
2841  /* location, and that the file name is the one associated with */
2842  /* the keyword itself (e.g., we're looking at attached data) */
2843  *start_location = atoi(first_word);
2844  CopyString(fname, keyword->file_name)
2845 
2846  } /* End: "if ((*first_word == '"') || ... else ..." */
2847 
2848  /* No unit string means a record location */
2849  if (unit == NULL)
2850  *start_location_type = ODL_RECORD_LOCATION;
2851  else
2852  {
2853  /* Otherwise, find out what kind of units string we have */
2854  UpperCase(unit)
2855  *unit = '<'; /* Bug fix SM 10/24/94 */
2856  if (strncmp(unit, "<BYTE", 5) == 0)
2857  *start_location_type = ODL_BYTE_LOCATION;
2858  else
2859  *start_location_type = ODL_RECORD_LOCATION;
2860  }
2861 
2862  LemmeGo(text)
2863 
2864  } /* End: "if (keyword != NULL) ..." */
2865 
2866  return(fname);
2867 
2868 } /* End: "OdlGetFileName" */
2869 
2870 
2871 
2872 
2873 /************************************************************************/
2874 /* */
2875 /* Component: */
2876 /* */
2877 /* OdlGetFileSpec */
2878 /* */
2879 /* Author: */
2880 /* */
2881 /* David P. Bernath (Jet Propulsion Laboratory) */
2882 /* */
2883 /* Version: */
2884 /* */
2885 /* 1.0 March 31, 1994 */
2886 /* */
2887 /* Change History: */
2888 /* */
2889 /* 03-31-94 Original code */
2890 /* */
2891 /*----------------------------------------------------------------------*/
2892 /* */
2893 /* Description: */
2894 /* */
2895 /* This routine is still TBD. It's supposed to locate a file */
2896 /* (whose name is passed in) by using the file search rules in the */
2897 /* PDS Standards Reference. At the moment it just looks in the */
2898 /* current directory. */
2899 /* */
2900 /* WARNING: This routine allocates memory to hold the file spec */
2901 /* that is returned. This memory will have to be freed. */
2902 /* */
2903 /************************************************************************/
2904 
2905 #ifdef _NO_PROTO
2906 
2907 char *OdlGetFileSpec (fname) /* this is still TBD */
2908 
2909 char *fname;
2910 
2911 #else
2912 
2913 char *OdlGetFileSpec (char *fname) /* this is still TBD */
2914 
2915 #endif
2916 {
2917  char *fspec = {NULL};
2918 
2919  if (fname != NULL)
2920  {
2921  /* this is still TBD */
2922  CopyString(fspec, fname)
2923  }
2924 
2925  return(fspec);
2926 
2927 } /* End: "OdlGetFileSpec" */
2928 
2929 
2930 
2931 
2932 
2933 /************************************************************************/
2934 /* */
2935 /* Component: */
2936 /* */
2937 /* OdlLocateStart */
2938 /* */
2939 /* Author: */
2940 /* */
2941 /* David P. Bernath (Jet Propulsion Laboratory) */
2942 /* */
2943 /* Version: */
2944 /* */
2945 /* 1.0 March 31, 1994 */
2946 /* */
2947 /* Change History: */
2948 /* */
2949 /* 03-31-94 Original code */
2950 /* */
2951 /*----------------------------------------------------------------------*/
2952 /* */
2953 /* Description: */
2954 /* */
2955 /* This routine opens the filespec passed in, and attempts to */
2956 /* find the start of the data by using the start_location and */
2957 /* location_type that were passed in. It returns a pointer to */
2958 /* the start of the data within the file. */
2959 /* */
2960 /************************************************************************/
2961 
2962 #ifdef _NO_PROTO
2963 
2964 FILE *OdlLocateStart (filespec, start_location, start_location_type)
2965 
2966 char *filespec;
2967 unsigned long start_location;
2968 unsigned short start_location_type;
2969 
2970 #else
2971 
2972 FILE *OdlLocateStart (char *filespec, unsigned long start_location,
2973  unsigned short start_location_type)
2974 
2975 #endif
2976 {
2977  FILE *fptr = {NULL};
2978  unsigned short reached_the_end = {FALSE};
2979  char buffer [TB_MAX_BUFFER]; /* Bug fix 11/2/94 SM: */
2980  /* Was TB_MAX_BUFFER + 1, which won't */
2981  /* compile on platforms with 2-byte ints, */
2982  /* because it's 1 bigger than than MAX_INT.*/
2983  unsigned long i;
2984 
2985  if (filespec != NULL)
2986  {
2987  if (start_location_type == ODL_BYTE_LOCATION)
2988  {
2989  fptr = (FILE *) fopen(filespec, "rb");
2990  if ((fptr != NULL) && (start_location > 1))
2991  reached_the_end = (fseek(fptr,start_location,0) != 0);
2992  }
2993  else
2994  {
2995  fptr = (FILE *) fopen(filespec, "r");
2996  if (fptr != NULL)
2997  {
2998  for (i=1; ((i < start_location) && (! reached_the_end)); ++i)
2999  {
3000  if (! fgets(buffer, TB_MAX_BUFFER, fptr))
3001  reached_the_end = TRUE;
3002  }
3003  }
3004 
3005  } /* End: "if (start_location_type == ... else ..." */
3006 
3007  if (reached_the_end) CloseMe(fptr)
3008 
3009  } /* End: "if (filespec != NULL) ..." */
3010 
3011  return(fptr);
3012 
3013 } /* End: "OdlGetFileSpec" */
3014 
3015 
3016 
3017 
3018 
3019 
3020 /*========================================================================*/
3021 /* */
3022 /* Print Routines */
3023 /* */
3024 /*========================================================================*/
3025 
3026 /************************************************************************/
3027 /* */
3028 /* Component: */
3029 /* */
3030 /* OdlPrintMessage */
3031 /* */
3032 /* Author: */
3033 /* */
3034 /* David P. Bernath (Jet Propulsion Laboratory) */
3035 /* */
3036 /* Version: */
3037 /* */
3038 /* 1.0 March 31, 1994 */
3039 /* */
3040 /* Change History: */
3041 /* */
3042 /* 03-31-94 Original code */
3043 /* */
3044 /*----------------------------------------------------------------------*/
3045 /* */
3046 /* Description: */
3047 /* */
3048 /* This routine prints a formatted message either to stdout or to */
3049 /* a message file, depending on what was passed in. Messages are */
3050 /* formatted to look like this: */
3051 /* */
3052 /* <line number> -- <message text> */
3053 /* */
3054 /* If the line_number is zero, then just the message text is */
3055 /* printed, with no formatting. */
3056 /* */
3057 /* If the odl_suppress_messages global flag is set to TRUE (1) */
3058 /* then nothing is printed. */
3059 /* */
3060 /************************************************************************/
3062 
3063 #ifdef _NO_PROTO
3064 
3065 short OdlPrintMessage (message_fname, message_fptr, line_number, text)
3066 
3067 const char *message_fname;
3068 FILE *message_fptr;
3069 long line_number;
3070 const char *text;
3071 
3072 #else
3073 
3074 short OdlPrintMessage (const char *message_fname, FILE *message_fptr,
3075  long line_number, const char *text)
3076 
3077 #endif
3078 {
3079  FILE *m_ptr = {NULL};
3080  char line_prompt[20];
3081  char *line_out = {NULL};
3082 
3084 
3085  if (! odl_suppress_messages)
3086  {
3087  m_ptr = (message_fptr != NULL) ? message_fptr :
3088  (FILE *) OdlOpenMessageFile(message_fname, message_fptr);
3089 
3090  if (line_number == 0)
3091  (void)strcpy(line_prompt, "");
3092  else
3093  (void)sprintf(line_prompt, " Line %ld -- ", line_number);
3094 
3095  if (text == NULL)
3096  {
3097  NewString(line_out, (20 + (long)strlen(line_prompt)))
3098  (void)sprintf(line_out, "%s Unknown error", line_prompt);
3099  }
3100  else
3101  {
3102  NewString(line_out, (20 + (long)strlen(line_prompt) + (long)strlen(text)))
3103  (void)sprintf(line_out, "%s%s", line_prompt, text);
3104  }
3105 
3106  line_out = OdlFormatMessage(line_out);
3107  (void)strcpy(ODLErrorMessage, line_out);
3108  (void)fprintf(m_ptr, "%s", line_out);
3109  LemmeGo(line_out)
3110 
3111  /* if we opened the message file in this routine then close it */
3112  if ((m_ptr != stdout) && (message_fptr == NULL))
3113  CloseMe(m_ptr)
3114 
3115  } /* End: "if (! odl_suppress_messages) ..." */
3116 
3117  return(FALSE);
3118 
3119 } /* End routine: OdlPrintMessage */
3120 
3121 /************************************************************************/
3122 /* */
3123 /* Component: */
3124 /* */
3125 /* OdlPrintLine */
3126 /* */
3127 /* Author: */
3128 /* */
3129 /* J. S. Hughes (Jet Propulsion Laboratory) */
3130 /* */
3131 /* Version: */
3132 /* */
3133 /* 1.0 February 20, 1995 */
3134 /* */
3135 /* Change History: */
3136 /* */
3137 /* 02-20-95 jsh - a copy of OdlPrintMessage cleaned up for */
3138 /* simple output of lines to message file */
3139 /* NOTE: '\n' is not appended or assumed */
3140 /* */
3141 /*----------------------------------------------------------------------*/
3142 /* */
3143 /* Description: */
3144 /* */
3145 /* This routine prints a simple line either to stdout or to */
3146 /* a message file, depending on what was passed in. */
3147 /* */
3148 /* If the odl_suppress_messages global flag is set to TRUE (1) */
3149 /* then nothing is printed. */
3150 /* */
3151 /************************************************************************/
3152 
3153 #ifdef _NO_PROTO
3154 
3155 short OdlPrintLine (message_fname, message_fptr, text)
3156 
3157 const char *message_fname;
3158 FILE *message_fptr;
3159 const char *text;
3160 
3161 #else
3162 
3163 short OdlPrintLine (const char *message_fname, FILE *message_fptr,
3164  const char *text)
3165 
3166 #endif
3167 {
3168  FILE *m_ptr = {NULL};
3169 
3170  if (! odl_suppress_messages)
3171  {
3172  m_ptr = (message_fptr != NULL) ? message_fptr :
3173  (FILE *) OdlOpenMessageFile(message_fname, message_fptr);
3174 
3175  if (text == NULL)
3176  {
3177  (void)fprintf(m_ptr, "%s", "Unknown error\n");
3178  }
3179  else
3180  {
3181  (void)fprintf(m_ptr, "%s", text);
3182  }
3183 
3184  /* if we opened the message file in this routine then close it */
3185  if ((m_ptr != stdout) && (message_fptr == NULL))
3186  CloseMe(m_ptr)
3187 
3188  } /* End: "if (! odl_suppress_messages) ..." */
3189 
3190  return(FALSE);
3191 
3192 } /* End routine: OdlPrintLine */
3193 
3194 
3195 /*******************/
3196 /* Local Routine */
3197 /*******************/
3198 
3199 #ifdef _NO_PROTO
3200 
3201 char *OdlFormatMessage (text)
3202 
3203 char *text;
3204 
3205 #else
3206 
3207 char *OdlFormatMessage (char *text)
3208 
3209 #endif
3210 {
3211  char *new_text = {NULL};
3212  char *first_char = {NULL};
3213  char *last_char = {NULL};
3214  char *dashes = {NULL};
3215  char *blanks = {NULL};
3216  char *c = {NULL};
3217  char save_it = {'\0'};
3218  long report_indent = {0};
3219  long report_width = {75};
3220  long line_size = {0};
3221  long len = {0};
3222  long i = {0};
3223 
3224  /* IF a message was passed in THEN */
3225  if (text != NULL)
3226  {
3227  NewString(new_text, 1)
3228 
3229  /* Find the double dash delimiter thingy in the message. */
3230  /* Messages will look something like this: */
3231  /* WARNING: Line 123 -- BANDS: Not in data dictionary. */
3232  /* We are using the location of the " -- " characters to */
3233  /* figure out how far the wrapped part of the line should */
3234  /* be indented. */
3235 
3236  if ((dashes = strstr(text, " -- ")) != NULL)
3237  report_indent = 4 + ((long) (dashes - text));
3238 
3239  if (report_indent >= (report_width - 2))
3240  report_indent = 0;
3241 
3242  /* Initialize the string of blanks used for indentation. */
3243  NewString(blanks, report_indent + 1)
3244  for (i=0; i < report_indent; ++i)
3245  *(blanks+i) = ' ';
3246  *(blanks+i) = '\0';
3247 
3248  /* Figure out the size of the wrapped parts of the line. */
3249  line_size = report_width - report_indent;
3250 
3251  /* Now that we have all that out of the way, we can LOOP through */
3252  /* the string until we have wrapped and written the */
3253  /* whole thing. */
3254  for (first_char=text; *first_char != '\0'; first_char = last_char)
3255  {
3256  /* Find the length of the remaining part of the string. */
3257  len = strlen(first_char);
3258 
3259  /* IF we are at the beginning of the string THEN */
3260  /* Use the total width of the report to figure out where */
3261  /* the end of the line should be. */
3262  /* ELSE */
3263  /* Write the blanks to the report file and use the space */
3264  /* left over after indentation to figure out where */
3265  /* the end of the line should be. */
3266  /* ENDIF */
3267 
3268  if (first_char == text)
3269  {
3270  if (len > report_width)
3271  last_char = (char *) (first_char + report_width);
3272  else
3273  last_char = (char *) (first_char + len);
3274  }
3275  else
3276  {
3277  AppendString(new_text, blanks)
3278 
3279  if (len > line_size)
3280  last_char = (char *) (first_char + line_size);
3281  else
3282  last_char = (char *) (first_char + len);
3283 
3284  } /* End: "if (first_char == text) ... else ..." */
3285 
3286  /* IF the current part of the message is still too large to */
3287  /* fit without wrapping THEN */
3288  /* Find the last blank in the line and wrap there. */
3289  /* ENDIF */
3290 
3291  if (*last_char != '\0')
3292  {
3293  for (c = last_char; ((c >= first_char) && (*c != ' ')); --c) ;
3294 
3295  if (c > first_char)
3296  last_char = c;
3297 
3298  } /* End: "if (*last_char != '\0') ..." */
3299 
3300  /* Append the current part of the message onto the new string */
3301  save_it = *last_char;
3302  *last_char = '\0';
3303  AppendString(new_text, first_char)
3304  AppendString(new_text, "\n")
3305  *last_char = save_it;
3306 
3307  /* Bypass the last blank character. */
3308  if (*last_char == ' ')
3309  ++last_char;
3310 
3311  } /* End: "for (first_char = text; ..." */
3312 
3313  /* Deallocate local storage. */
3314  LemmeGo(blanks)
3315 
3316  } /* End: "if ((text != NULL) && ..." */
3317 
3318  LemmeGo(text)
3319 
3320  return(new_text);
3321 
3322 } /* End routine: "OdlFormatMessage" */
3323 
3324 
3325 
3326 
3327 /************************************************************************/
3328 /* */
3329 /* Component: */
3330 /* */
3331 /* OdlPrintHierarchy */
3332 /* */
3333 /* Author: */
3334 /* */
3335 /* David P. Bernath (Jet Propulsion Laboratory) */
3336 /* */
3337 /* Version: */
3338 /* */
3339 /* 1.0 March 31, 1994 */
3340 /* */
3341 /* Change History: */
3342 /* */
3343 /* 03-31-94 Original code */
3344 /* */
3345 /*----------------------------------------------------------------------*/
3346 /* */
3347 /* Description: */
3348 /* */
3349 /* This routine prints the object hierarchy to a message file. */
3350 /* */
3351 /************************************************************************/
3352 
3353 #ifdef _NO_PROTO
3354 
3355 void OdlPrintHierarchy (object, message_fname, message_fptr)
3356 
3357 OBJDESC *object;
3358 char *message_fname;
3359 FILE *message_fptr;
3360 
3361 #else
3362 
3363 void OdlPrintHierarchy (OBJDESC *object, char *message_fname,
3364  FILE *message_fptr)
3365 
3366 #endif
3367 {
3368  OBJDESC *obj = {NULL};
3369  KEYWORD *kwd = {NULL};
3370  FILE *m_ptr = {NULL};
3371  char *format = {NULL};
3372  const char *no_name = {"<no name>"};
3373  char msgtext [TB_MAXLINE + 1];
3374 
3375  m_ptr = (message_fptr != NULL) ? message_fptr :
3376  (FILE *) OdlOpenMessageFile(message_fname, message_fptr);
3377 
3378  for (obj=object; obj != NULL; obj=(OBJDESC *) OdlTraverseTree(obj, object->level))
3379  {
3380  NewString(format, (TB_MAXLINE + 1))
3381 
3382  kwd = (KEYWORD *)OdlFindKwd(obj, "NAME", (char *)NULL,(long)1, ODL_THIS_OBJECT);
3383 
3384  if ((kwd == NULL) || (kwd->value == NULL))
3385  {
3386  (void)sprintf(format, " Line %-5lu %%%lud %%%lus",
3387  obj->line_number, (obj->level + 1),
3388  (2*(obj->level) + strlen(no_name)));
3389 
3390  (void)sprintf(msgtext, format, obj->level, no_name);
3391  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
3392  }
3393  else
3394  {
3395  (void)sprintf(format, " Line %-5lu %%%lud %%%lus",
3396  obj->line_number, (obj->level + 1),
3397  (2*(obj->level) + strlen(kwd->value)));
3398  (void)sprintf(msgtext, format, obj->level, kwd->value);
3399  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
3400  }
3401 
3402  if (obj->class == NULL)
3403  (void)OdlPrintLine(message_fname, m_ptr, " -- <no class>\n");
3404  else {
3405  (void)sprintf(msgtext, " -- %s\n", obj->class);
3406  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
3407  }
3408 
3409  LemmeGo(format)
3410 
3411  } /* End: "for (obj=object; ..." */
3412 
3413  /* if we opened the message file in this routine then close it */
3414  if ((m_ptr != stdout) && (message_fptr == NULL))
3415  CloseMe(m_ptr)
3416 
3417  return;
3418 
3419 } /* End routine: "OdlPrintHierarchy" */
3420 
3421 
3422 
3423 
3424 /************************************************************************/
3425 /* */
3426 /* Component: */
3427 /* */
3428 /* OdlPrintLabel */
3429 /* */
3430 /* Author: */
3431 /* */
3432 /* David P. Bernath (Jet Propulsion Laboratory) */
3433 /* */
3434 /* Version: */
3435 /* */
3436 /* 1.0 March 31, 1994 */
3437 /* */
3438 /* Change History: */
3439 /* */
3440 /* 03-31-94 Original code */
3441 /* 03-11-97 Add GROUP logic */
3442 /* */
3443 /*----------------------------------------------------------------------*/
3444 /* */
3445 /* Description: */
3446 /* */
3447 /* This routine prints the ODL tree to a message file, in ODL */
3448 /* format, unless the global odl_suppress_messages flag is set. */
3449 /* */
3450 /************************************************************************/
3451 
3452 #ifdef _NO_PROTO
3453 
3454 void OdlPrintLabel (object, message_fname, message_fptr, root_level)
3455 
3456 OBJDESC *object;
3457 char *message_fname;
3458 FILE *message_fptr;
3459 unsigned long root_level;
3460 
3461 #else
3462 
3463 void OdlPrintLabel (OBJDESC *object, char *message_fname, FILE *message_fptr,
3464  unsigned long root_level)
3465 
3466 #endif
3467 {
3468  FILE *m_ptr = {NULL};
3469  char *blanks = {NULL};
3470  int i;
3471  char msgtext [TB_MAXLINE + 1];
3472 
3473  if (! odl_suppress_messages)
3474  {
3475  m_ptr = (message_fptr != NULL) ? message_fptr :
3476  (FILE *) OdlOpenMessageFile(message_fname, message_fptr);
3477  if (object != NULL)
3478  {
3479  NewString(blanks, (4*object->level))
3480  for (i=1; i < object->level; ++i) (void)strcat(blanks, " ");
3481 
3482  if (object->pre_comment != NULL)
3483  (void)OdlPrintLine(message_fname, m_ptr, object->pre_comment);
3484 
3485  if (object->parent != NULL)
3486  {
3487  if (object->is_a_group == ODL_OBJECT)
3488  {
3489  if (object->class == NULL) {
3490  (void)sprintf(msgtext, "%sOBJECT", blanks);
3491  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
3492  }
3493  else {
3494  (void)sprintf(msgtext, "%sOBJECT = %s", blanks, object->class);
3495  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
3496  }
3497  }
3498  else
3499  {
3500  if (object->class == NULL) {
3501  (void)sprintf(msgtext, "%sGROUP", blanks);
3502  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
3503  }
3504  else {
3505  (void)sprintf(msgtext, "%sGROUP = %s", blanks, object->class);
3506  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
3507  }
3508  }
3509 
3510  if (object->line_comment != NULL) {
3511  (void)OdlPrintLine(message_fname, m_ptr, " ");
3512  (void)OdlPrintLine(message_fname, m_ptr, object->line_comment);
3513  }
3514 
3515  (void)OdlPrintLine(message_fname, m_ptr, "\n");
3516 
3517  } /* End: "if (object->parent != NULL) ..." */
3518 
3519  OdlPrintKeywords(object, NULL, m_ptr);
3520  OdlPrintLabel(object->first_child, (char *)NULL, m_ptr, root_level);
3521 
3522  if (object->post_comment != NULL)
3523  (void)OdlPrintLine(message_fname, m_ptr, object->post_comment);
3524 
3525  if (object->parent != NULL)
3526  {
3527  if (object->is_a_group == ODL_OBJECT)
3528  {
3529  if (object->class == NULL) {
3530  (void)sprintf(msgtext, "%sEND_OBJECT", blanks);
3531  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
3532  }
3533  else {
3534  (void)sprintf(msgtext, "%sEND_OBJECT = %s", blanks, object->class);
3535  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
3536  }
3537  }
3538  else
3539  {
3540  if (object->class == NULL) {
3541  (void)sprintf(msgtext, "%sEND_GROUP", blanks);
3542  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
3543  }
3544  else {
3545  (void)sprintf(msgtext, "%sEND_GROUP = %s", blanks, object->class);
3546  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
3547  }
3548  }
3549 
3550  if (object->end_comment != NULL) {
3551  (void)OdlPrintLine(message_fname, m_ptr, " ");
3552  (void)OdlPrintLine(message_fname, m_ptr, object->end_comment);
3553  }
3554 
3555  (void)OdlPrintLine(message_fname, m_ptr, "\n");
3556 
3557  } /* End: "if (object->parent != NULL) ..." */
3558 
3559  if (object->level > root_level)
3560  OdlPrintLabel(object->right_sibling, (char *)0, m_ptr, root_level);
3561 
3562  LemmeGo(blanks)
3563 
3564  if (object->parent == NULL)
3565  (void)OdlPrintLine(message_fname, m_ptr, "END\n");
3566 
3567  } /* End: "if (object != NULL) ..." */
3568 
3569  /* if we opened the message file in this routine then close it */
3570  if ((m_ptr != stdout) && (message_fptr == NULL))
3571  CloseMe(m_ptr)
3572 
3573  } /* End: "if (! odl_suppress_messages) ..." */
3574 
3575  return;
3576 
3577 } /* End routine: "OdlPrintLabel" */
3578 
3579 
3580 
3581 /*******************/
3582 /* Local Routine */
3583 /*******************/
3584 
3585 #ifdef _NO_PROTO
3586 
3587 void OdlPrintKeywords (object, message_fname, message_fptr)
3588 
3589 OBJDESC *object;
3590 char *message_fname;
3591 FILE *message_fptr;
3592 
3593 #else
3594 
3595 void OdlPrintKeywords (OBJDESC *object, char *message_fname,
3596  FILE *message_fptr)
3597 
3598 #endif
3599 {
3600  KEYWORD *keyword = {NULL};
3601  FILE *m_ptr = {NULL};
3602  short sfdu_only = {FALSE};
3603  char *blanks = {NULL};
3604  int i;
3605 
3606  m_ptr = (message_fptr != NULL) ? message_fptr :
3607  (FILE *) OdlOpenMessageFile(message_fname, message_fptr);
3608 
3609  if (object != NULL)
3610  {
3611  NewString(blanks, (4*object->level))
3612  if (object->level > 0)
3613  for (i=0; i < object->level; ++i) (void)strcat(blanks, " ");
3614 
3615  for (keyword=object->first_keyword; keyword != NULL;
3616  keyword = keyword->right_sibling)
3617  {
3618  if (keyword->pre_comment != NULL)
3619  (void)OdlPrintLine(message_fname, m_ptr, keyword->pre_comment);
3620 
3621  (void)OdlPrintLine(message_fname, m_ptr, blanks);
3622 
3623  sfdu_only = FALSE;
3624  if (keyword->name == NULL)
3625  (void)OdlPrintLine(message_fname, m_ptr, "unknown_keyword");
3626  else
3627  {
3628  (void)OdlPrintLine(message_fname, m_ptr, keyword->name);
3629  sfdu_only = ((strncmp(keyword->name, "NJPL", 4) == 0) ||
3630  (strncmp(keyword->name, "CCSD", 4) == 0));
3631  }
3632 
3633  if ((keyword->value != NULL) && (! sfdu_only)) {
3634  (void)OdlPrintLine(message_fname, m_ptr, " = ");
3635  (void)OdlPrintLine(message_fname, m_ptr, keyword->value);
3636  }
3637 
3638  if (keyword->line_comment != NULL) {
3639  (void)OdlPrintLine(message_fname, m_ptr, " ");
3640  (void)OdlPrintLine(message_fname, m_ptr, keyword->line_comment);
3641  }
3642 
3643  (void)OdlPrintLine(message_fname, m_ptr, "\n");
3644 
3645  } /* End: "for (keyword=object ..." */
3646 
3647  LemmeGo(blanks)
3648 
3649  } /* End: "if (object != NULL) ..." */
3650 
3651  /* if we opened the message file in this routine then close it */
3652  if ((m_ptr != stdout) && (message_fptr == NULL))
3653  CloseMe(m_ptr)
3654 
3655  return;
3656 
3657 } /* End routine: "OdlPrintKeywords" */
3658 
3659 
3660 
3661 
3662 /*========================================================================*/
3663 /* */
3664 /* Parser-specific routines */
3665 /* */
3666 /*========================================================================*/
3667 
3668 
3669 /************************************************************************/
3670 /* */
3671 /* Component: */
3672 /* */
3673 /* OdlParseFile */
3674 /* */
3675 /* Author: */
3676 /* */
3677 /* David P. Bernath (Jet Propulsion Laboratory) */
3678 /* */
3679 /* Version: */
3680 /* */
3681 /* 1.0 March 31, 1994 */
3682 /* */
3683 /* Change History: */
3684 /* */
3685 /* 03-31-94 Original code */
3686 /* 03-11/97 Add GROUPS objects */
3687 /*----------------------------------------------------------------------*/
3688 /* */
3689 /* Description: */
3690 /* */
3691 /* This routine actually does the parsing of a label file and */
3692 /* returns a pointer to the root object of the tree. */
3693 /* */
3694 /************************************************************************/
3695 
3696 #ifdef _NO_PROTO
3697 
3698 OBJDESC *OdlParseFile(label_fname, label_fptr, message_fname, message_fptr,
3699  suppress_messages, suppress_metrics, suppress_hierarchy,
3700  ignore_missing_end)
3701 
3702 char *label_fname;
3703 FILE *label_fptr;
3704 char *message_fname;
3705 FILE *message_fptr;
3706 unsigned short suppress_messages;
3707 unsigned short suppress_metrics;
3708 unsigned short suppress_hierarchy;
3709 unsigned short ignore_missing_end;
3710 
3711 #else
3712 
3713 OBJDESC *OdlParseFile( char *label_fname, FILE *label_fptr,
3714  char *message_fname, FILE *message_fptr,
3715  unsigned short suppress_messages,
3716  unsigned short suppress_metrics,
3717  unsigned short suppress_hierarchy,
3718  unsigned short ignore_missing_end)
3719 
3720 #endif
3721 
3722 {
3723  OBJDESC *root = {NULL};
3724  OBJDESC *curr_object = {NULL};
3725  KEYWORD *curr_keyword = {NULL};
3726  FILE *m_ptr = {NULL};
3727  FILE *l_ptr = {NULL};
3728  char *left_part = {NULL};
3729  char *equals = {NULL};
3730  char *right_part = {NULL};
3731  char *comment = {NULL};
3732  char *c = {NULL};
3733  char *tc = {NULL};
3734  char *tintext = {NULL};
3735  char *text = {NULL};
3736  char line_comment [TB_MAXLINE + 1];
3737  char intext [TB_MAXLINE + 1];
3738  char msgtext [TB_MAXLINE + 1];
3739  long line_number = {0};
3740  long value_list_line_number = {0};
3741  long object_count = {0};
3742  long end_object_count = {0};
3743  long keyword_count = {0};
3744  long comment_count = {0};
3745  long brace_nesting = {0};
3746  long paren_nesting = {0};
3747  short end_found = {FALSE};
3748  short value_list = {FALSE};
3749  short equals_found = {FALSE};
3750  short val_found = {FALSE};
3751  short balanced = {FALSE};
3752  short oddquotes = {FALSE};
3753  unsigned short is_a_group;
3754 
3755  odl_message_count = 0;
3756  odl_suppress_messages = suppress_messages;
3757 
3758  /* either use the file pointer passed in or open the message file */
3759  m_ptr = (message_fptr != NULL) ? message_fptr :
3760  (FILE *) OdlOpenMessageFile(message_fname, message_fptr);
3761  /* opening remarks */
3762  if (label_fname == NULL)
3763  (void)sprintf(msgtext, "Parsing File: (no file name provided)");
3764  else
3765  (void)sprintf(msgtext, "Parsing File: %s", label_fname);
3766 
3767  (void)OdlPrintLine(message_fname, m_ptr, "\n--------------------------------------------------------------------------\n");
3768  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
3769  (void)OdlPrintLine(message_fname, m_ptr, "\n--------------------------------------------------------------------------\n\n");
3770 
3771  /* either use the file pointer passed in or open the label file */
3772  l_ptr = (label_fptr != NULL) ? label_fptr :
3773  (label_fname == NULL) ? NULL :
3774  (FILE *) fopen(label_fname,"r");
3775  if (l_ptr == NULL)
3776  {
3777  (void)OdlPrintMessage(message_fname, m_ptr, (long)0,
3778  "Unable to open the label file. Parsing cannot continue");
3779  }
3780  else
3781  {
3782  NewString(comment, 1)
3783 
3784  /* Initialize a ROOT object to start the tree */
3785  curr_object = root = OdlNewObjDesc("ROOT",(char *)0,(char *)0,(char *)0,(char *)0,label_fname,0,(long)0);
3786 
3787  /* read the label file */
3788  while (! end_found && fgets(intext, TB_MAXLINE, l_ptr))
3789  {
3790  ++line_number;
3791 
3792  StripUnprintables(intext) /* removes linefeeds and such */
3793  ReplaceChar(intext, ' ', ' ') /* turns TABs into blanks */
3794  StripTrailing(intext, ' ') /* removes trailing blanks */
3795 
3796  /* locate and skip SFDU */
3797 
3798  if (line_number == 1L)
3799  {
3800  if (! strncmp(intext, "CCSD", 4))
3801  continue;
3802  }
3803 
3804  /* locate, save, and remove comment text from the line */
3805  *line_comment = '\0';
3806  tintext = intext;
3807  oddquotes = FALSE;
3808  while ((c = strstr(tintext, "/*")) != NULL)
3809  {
3810  for (tc = tintext; tc < c; tc++)
3811  if (*tc == '"')
3812  {
3813  if (oddquotes) oddquotes = FALSE;
3814  else oddquotes = TRUE;
3815  }
3816  if (! oddquotes)
3817  {
3818  oddquotes = FALSE;
3819  ++comment_count;
3820  (void)strcpy(line_comment, c);
3821  *c = '\0';
3822  StripTrailing(tintext, ' ');
3823  break;
3824  }
3825  else
3826  tintext = c+1;
3827  }
3828 
3829  c = OdlFirstWord(intext);
3830 
3831  if (text != NULL || *c != '\0')
3832  {
3833  AppendString(text, intext)
3834 
3835  c = OdlFirstWord(text);
3836 
3837  if (strcmp(c, "END") == 0)
3838  {
3839  balanced = TRUE;
3840  end_found = TRUE;
3841  break;
3842  }
3843  else
3844  if (strcmp(c, "END_OBJECT") == 0 || strcmp(c, "END_GROUP") == 0 )
3845  {
3846  balanced = TRUE;
3847  }
3848  else
3849  {
3850  if (! equals_found)
3851  equals_found = (strchr(text, '=') != NULL);
3852 
3853  if (! val_found && equals_found)
3854  {
3855  c = (char *) LastChar(text);
3856  val_found = (*c != '=');
3857  }
3858 
3859  if (val_found && equals_found)
3860  balanced = CheckBalance(text);
3861 
3862  if (! balanced)
3863  AppendString(text, "\n")
3864  }
3865  }
3866 
3867  if (balanced)
3868  {
3869  /* locate the keyword, the equals sign, and the value */
3870  left_part = OdlFirstWord(text);
3871 
3872  if ((equals = (char *)strchr(left_part, '=')) != NULL)
3873  right_part = OdlFirstWord(equals+1);
3874  else
3875  {
3876  equals = text + strlen(text);
3877  right_part = equals;
3878  }
3879 
3880  /*------------------------------------------------------------------*/
3881  /* Here's where the parsing begins. First, we take care of three */
3882  /* special cases: multi-line quoted values, multi-line value */
3883  /* lists, and blank lines. If the current line isn`t one */
3884  /* of these than it's either an OBJECT statement, an END_OBJECT */
3885  /* statement, the END of the label, or a new KEYWORD. */
3886  /*------------------------------------------------------------------*/
3887 
3888  /* we've discovered the beginning of a new object */
3889  if ((strncmp(left_part, "OBJECT ", 7) == 0) || (strcmp(left_part, "OBJECT") == 0) ||
3890  (strncmp(left_part, "GROUP ", 6) == 0) || (strcmp(left_part, "GROUP") == 0))
3891 
3892  {
3893  ++object_count;
3894  ++(curr_object->child_count);
3895 
3896  if ((strncmp(left_part, "OBJECT ", 7) == 0) || (strcmp(left_part, "OBJECT") == 0))
3897  is_a_group = ODL_OBJECT;
3898  else
3899  is_a_group = ODL_GROUP;
3900 
3901  /* validate the new object's class identifier */
3902  (void)OdlValidObjDesc(curr_object, equals, right_part,
3903  message_fname, m_ptr, line_number);
3904 
3905  /* make the new object a child of the current object */
3906  curr_object = OdlPasteObjDesc(OdlNewObjDesc(right_part,
3907  comment,line_comment,(char *)0,(char *)0,
3908  label_fname,is_a_group,line_number),
3909  curr_object);
3910 
3911  /* reset the comment text string */
3912  LemmeGo(comment)
3913  NewString(comment, 1)
3914  }
3915  else
3916  /*------------------------------------------------------------------*/
3917  /* we've discovered the end of the current object */
3918  if ((strncmp(left_part, "END_OBJECT ", 11) == 0) || (strcmp(left_part, "END_OBJECT") == 0) ||
3919  (strncmp(left_part, "END_GROUP ", 10) == 0) || (strcmp(left_part, "END_GROUP") == 0))
3920  {
3921  ++end_object_count;
3922 
3923  if ((strncmp(left_part, "END_OBJECT ", 11) == 0) || (strcmp(left_part, "END_OBJECT") == 0))
3924  is_a_group = ODL_OBJECT;
3925  else
3926  is_a_group = ODL_GROUP;
3927 
3928  /* validate the end_object's class identifier */
3929  (void)OdlValidEndObjDesc(curr_object, equals, right_part,
3930  message_fname, m_ptr, line_number, is_a_group);
3931 
3932  /* set the current object's remaining comment fields */
3933  CopyString(curr_object->post_comment, comment)
3934  CopyString(curr_object->end_comment, line_comment)
3935 
3936  /* make curr object's parent the new current object */
3937  if (curr_object->parent != NULL)
3938  curr_object = curr_object->parent;
3939 
3940  /* reset the comment text string */
3941  LemmeGo(comment)
3942  NewString(comment, 1)
3943  }
3944  else
3945  /*------------------------------------------------------------------*/
3946  /* we've reached the end of the label */
3947  if ((strncmp(left_part, "END ", 4) == 0) ||
3948  (strcmp(left_part, "END") == 0))
3949  {
3950  end_found = TRUE;
3951  CopyString(curr_object->post_comment, comment)
3952  }
3953  else
3954  /*------------------------------------------------------------------*/
3955  /* We've discovered a keyword and its value */
3956  {
3957  ++keyword_count;
3958 
3959  /* validate the keyword and its values */
3960  (void)OdlValidKwd(curr_object, left_part, equals,
3961  right_part, message_fname, m_ptr, line_number);
3962 
3963  /* Add the keyword to the current object */
3964  curr_keyword = OdlPasteKwd(OdlNewKwd(left_part, right_part,
3965  comment, line_comment,
3966  label_fname, line_number),
3967  curr_object);
3968 
3969  /* we've got a potential multi-line value list if the
3970  first character of the value is either an open
3971  brace, '{', or an open paren, '('
3972  */
3973 
3974  if ((value_list = curr_keyword->is_a_list) == TRUE)
3975  {
3976  /* validate that the braces and parens are correct */
3977  (void)OdlValidBraces(curr_keyword->value,
3978  brace_nesting, paren_nesting,
3979  message_fname, m_ptr,
3980  value_list_line_number);
3981 
3982 
3983  /* reset the comment text string */
3984  LemmeGo(comment)
3985  NewString(comment, 1)
3986 
3987  } /* End: "if ((strncmp(left_part, ... else ... else ..." */
3988  /*------------------------------------------------------------------*/
3989  } /* End: "if (quoted_value) ... else ... else ..." */
3990 
3991  equals_found = FALSE;
3992  val_found = FALSE;
3993  balanced = FALSE;
3994  LemmeGo(text)
3995 
3996  }
3997  /*------------------------------------------------------------------*/
3998  } /* End: "while (fgets(text, ..." */
3999 
4000  /* if we're not sitting at the root then not enough END_OBJECTs found */
4001  if (curr_object->parent != NULL)
4002  {
4003  (void)OdlPrintMessage(message_fname, m_ptr, line_number,
4004  "Not enough END_OBJECT statements. Some objects may be incomplete");
4005  }
4006 
4007  /* hey, we didn't find an end statement! */
4008  if ((! end_found) && (! ignore_missing_end))
4009  {
4010  (void)OdlPrintMessage(message_fname, m_ptr, line_number,
4011  "END statement is missing");
4012  }
4013 
4014  /* oops, there was nothing in the label file to parse */
4015  if (line_number == 0)
4016  root = OdlFreeTree(root);
4017 
4018  LemmeGo(comment)
4019 
4020  } /* End: "if (l_ptr == NULL) ... else ..." */
4021 
4022  /* how'd we do? */
4023  if (! suppress_metrics && ! suppress_messages)
4024  {
4025  (void)OdlPrintLine(message_fname, m_ptr, "\n");
4026  (void)OdlPrintLine(message_fname, m_ptr, " |-------------------------------|\n");
4027  (void)OdlPrintLine(message_fname, m_ptr, " | Parsing Metrics: |\n");
4028  (void)OdlPrintLine(message_fname, m_ptr, " | |\n");
4029  (void)sprintf(msgtext, " | %7ld Syntax Messages |\n", odl_message_count);
4030  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
4031  (void)OdlPrintLine(message_fname, m_ptr, " | |\n");
4032  (void)sprintf(msgtext, " | %7ld OBJECT Statements |\n", object_count);
4033  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
4034  (void)sprintf(msgtext, " | %7ld END_OBJECT Statements |\n", end_object_count);
4035  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
4036  (void)sprintf(msgtext, " | %7ld Keywords |\n", keyword_count);
4037  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
4038  (void)sprintf(msgtext, " | %7ld Comments |\n", comment_count);
4039  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
4040  (void)OdlPrintLine(message_fname, m_ptr, " |-------------------------------|\n\n");
4041 
4042  } /* End: "if (! suppress_metrics) ..." */
4043 
4044  /* display the object hierarchy */
4045  if (! suppress_hierarchy && ! suppress_messages)
4046  {
4047  if (label_fname == NULL)
4048  (void)sprintf(msgtext, "Object Hierarchy in File: (no file name provided)");
4049  else
4050  (void)sprintf(msgtext, "Object Hierarchy in File: %s", label_fname);
4051 
4052  (void)OdlPrintLine(message_fname, m_ptr, "\n--------------------------------------------------------------------------\n");
4053  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
4054  (void)OdlPrintLine(message_fname, m_ptr, "\n--------------------------------------------------------------------------\n\n");
4055 
4056  OdlPrintHierarchy(root, message_fname, m_ptr);
4057 
4058  } /* End: "if (suppress_hierarchy) ..." */
4059 
4060  /* closing remarks */
4061 
4062 
4063 
4064  if (label_fname == NULL)
4065  (void)sprintf(msgtext, "End of Parsing File: (no file name provided)");
4066  else
4067  (void)sprintf(msgtext, "End of Parsing File: %s", label_fname);
4068 
4069  (void)OdlPrintLine(message_fname, m_ptr, "\n--------------------------------------------------------------------------\n");
4070  (void)OdlPrintLine(message_fname, m_ptr, msgtext);
4071  (void)OdlPrintLine(message_fname, m_ptr, "\n--------------------------------------------------------------------------\n\n");
4072 
4073  /* if we opened the label file in this routine then close it */
4074  if (label_fptr == NULL)
4075  CloseMe(l_ptr)
4076 
4077  /* if we opened the message file in this routine then close it */
4078  if ((m_ptr != stdout) && (message_fptr == NULL))
4079  CloseMe(m_ptr)
4080 
4081  LemmeGo(text)
4082 
4083  return (root);
4084 
4085 } /* End routine: OdlParseFile */
4086 
4087 
4088 /*******************/
4089 /* Local Routine */
4090 /*******************/
4091 
4092 #ifdef _NO_PROTO
4093 
4094 short OdlNestingLevel (text, brace_nesting, paren_nesting)
4095 char *text;
4096 long *brace_nesting;
4097 long *paren_nesting;
4098 
4099 #else
4100 
4101 short OdlNestingLevel (char *text, long *brace_nesting,
4102  long *paren_nesting)
4103 
4104 #endif
4105 {
4106  char *c = {NULL};
4107 
4108  for (c=text; *c != '\0'; ++c)
4109  {
4110  if (*c == '{')
4111  ++(*brace_nesting);
4112  else
4113  if (*c == '}')
4114  --(*brace_nesting);
4115  else
4116  if (*c == '(')
4117  ++(*paren_nesting);
4118  else
4119  if (*c == ')')
4120  --(*paren_nesting);
4121  }
4122 
4123  return((*brace_nesting == 0) && (*paren_nesting == 0));
4124 
4125 } /* End routine: "OdlNestingLevel" */
4126 
4127 
4128 /*******************/
4129 /* Local Routine */
4130 /*******************/
4131 
4132 #ifdef _NO_PROTO
4133 
4134 short OdlValidBraces (text, brace_nesting, paren_nesting,
4135  message_fname, message_fptr, line_number)
4136 
4137 char *text;
4138 long brace_nesting;
4139 long paren_nesting;
4140 char *message_fname;
4141 FILE *message_fptr;
4142 long line_number;
4143 
4144 #else
4145 
4146 short OdlValidBraces (char *text, long brace_nesting,
4147  long paren_nesting, char *message_fname,
4148  FILE *message_fptr, long line_number)
4149 
4150 #endif
4151 {
4152  char *c = {NULL};
4153  char *sp = {NULL};
4154  char *nesting_stack = {NULL};
4155  short status = {TRUE};
4156 
4157  /* allocate storage for the nesting stack */
4158  NewString(nesting_stack, (long)strlen(text))
4159 
4160  /* validate that all braces and parens are correctly nested */
4161  for (c=text,sp=(nesting_stack-1); ((*c != '\0') && (status == TRUE)); ++c)
4162  {
4163  /* push brace or paren onto the nesting stack */
4164  if ((*c == '{') || (*c == '('))
4165  *(++sp) = *c;
4166  else
4167  /* nesting is ok so far, pop the nesting stack */
4168  if (((*c == '}') && (*sp == '{')) || ((*c == ')') && (*sp == '(')))
4169  --sp;
4170  else
4171  /* found a right brace that doesn't have a matching left one */
4172  if ((*c == '}') && (*sp != '{'))
4173  {
4174  status = OdlPrintMessage(message_fname,message_fptr,line_number,
4175  "Bad nesting in VALUE LIST. Expected a right parenthesis and found a brace instead.");
4176  }
4177  else
4178  /* found a right paren that doesn't have a matching left one */
4179  if ((*c == ')') && (*sp != '('))
4180  {
4181  status = OdlPrintMessage(message_fname,message_fptr,line_number,
4182  "Bad nesting in VALUE LIST. Expected a right brace and found a parenthesis instead.");
4183  }
4184 
4185  /* we've reached nesting level zero before reaching the end */
4186  if ((sp < nesting_stack) && (*(c+1) != '\0'))
4187  {
4188  status = OdlPrintMessage(message_fname,message_fptr,line_number,
4189  "VALUE LIST not properly enclosed in braces or parentheses");
4190  }
4191 
4192  } /* End: "for (c=text,sp=(nesting_stack-1); ..." */
4193 
4194  LemmeGo(nesting_stack)
4195 
4196  if (brace_nesting < 0)
4197  {
4198  status = OdlPrintMessage(message_fname, message_fptr, line_number,
4199  "Too many right braces in VALUE LIST");
4200  }
4201  else
4202  if (brace_nesting > 0)
4203  {
4204  status = OdlPrintMessage(message_fname, message_fptr, line_number,
4205  "Too many left braces in VALUE LIST");
4206  }
4207 
4208  if (paren_nesting < 0)
4209  {
4210  status = OdlPrintMessage(message_fname, message_fptr, line_number,
4211  "Too many right parentheses in VALUE LIST");
4212  }
4213  else
4214  if (paren_nesting > 0)
4215  {
4216  status = OdlPrintMessage(message_fname, message_fptr, line_number,
4217  "Too many left parentheses in VALUE LIST");
4218  }
4219 
4220  return(status);
4221 
4222 } /* End routine: "OdlValidBraces" */
4223 
4224 
4225 /*******************/
4226 /* Local Routine */
4227 /*******************/
4228 
4229 #ifdef _NO_PROTO
4230 
4231 short OdlValidElement (text, message_fname, message_fptr, line_number,
4232  element_number)
4233 char *text;
4234 char *message_fname;
4235 FILE *message_fptr;
4236 long line_number;
4237 long element_number;
4238 
4239 #else
4240 
4241 short OdlValidElement (char *text, char *message_fname,
4242  FILE *message_fptr, long line_number,
4243  long element_number)
4244 
4245 #endif
4246 {
4247  char *message = NULL;
4248  char element_prompt[TB_MAXLINE + 1];
4249  char *save_units = 0;
4250  //char *first_blank = {NULL};
4251  char *first_char = {NULL};
4252  char *last_char = {NULL};
4253  char *units_start = {NULL};
4254  char *units_end = {NULL};
4255  char *single_quote = {NULL};
4256  char *double_quote = {NULL};
4257  short status = {TRUE};
4258 
4259  if (element_number <= 0)
4260  (void)strcpy(element_prompt, "");
4261  else
4262  (void)sprintf(element_prompt, " LIST element %ld", element_number);
4263 
4264  single_quote = (char *) strchr(text+1, (int) '\'');
4265  double_quote = (char *) strchr(text+1, (int) '"');
4266  //first_blank = (char *) strchr(text+1, (int) ' ');
4267  first_char = text;
4268  last_char = (char *) LastChar(text);
4269 
4270  NewString(message, (TB_MAXLINE+(long)strlen(text)))
4271 
4272  /* double quote found in the middle of the value */
4273  if ((double_quote > first_char) && (double_quote < last_char))
4274  {
4275  (void)sprintf(message, "Embedded double quote in VALUE%s", element_prompt);
4276  status = OdlPrintMessage(message_fname, message_fptr, line_number, message);
4277  }
4278  else
4279  /* value is double quoted - everything is okay */
4280  if (*first_char == '"')
4281  {
4282  status = TRUE;
4283  }
4284  else
4285  /* single quote found in the middle of the value */
4286  if ((single_quote > first_char) && (single_quote < last_char))
4287  {
4288  (void)sprintf(message, "Embedded single quote in VALUE%s", element_prompt);
4289  status = OdlPrintMessage(message_fname,message_fptr, line_number, message);
4290  }
4291  else
4292  /* value is single quoted - fine if not just a quote */
4293  if ((*first_char == '\'') && (*last_char == '\''))
4294  {
4295  if (first_char == last_char)
4296  {
4297  (void)sprintf(message, "Unpaired single quote in VALUE%s", element_prompt);
4298  status = OdlPrintMessage(message_fname,message_fptr, line_number, message);
4299  }
4300  }
4301  else
4302  /* value is missing a closing single quote */
4303  if ((*first_char == '\'') && (*last_char != '\''))
4304  {
4305  (void)sprintf(message, "Unpaired single quote in VALUE%s", element_prompt);
4306  status = OdlPrintMessage(message_fname,message_fptr, line_number, message);
4307  }
4308  else
4309  /* value is missing an opening single quote */
4310  if ((*first_char != '\'') && (*last_char == '\''))
4311  {
4312  (void)sprintf(message, "Unpaired single quote in VALUE%s", element_prompt);
4313  status = OdlPrintMessage(message_fname,message_fptr, line_number, message);
4314  }
4315  else
4316  /* value is missing an opening double quote */
4317  if ((*first_char != '"') && (*last_char == '"'))
4318  {
4319  (void)sprintf(message, "Unpaired double quote in VALUE%s", element_prompt);
4320  status = OdlPrintMessage(message_fname,message_fptr, line_number, message);
4321  }
4322  else
4323  /* current value list element is just a double quote */
4324  if ((element_number > 0) &&
4325  (first_char == (last_char-1)) && (*first_char == '"'))
4326  {
4327  (void)sprintf(message, "Unpaired double quote in VALUE%s", element_prompt);
4328  status = OdlPrintMessage(message_fname,message_fptr, line_number, message);
4329  }
4330  else
4331  /* current value list element is missing a closing double quote */
4332  if ((element_number > 0) &&
4333  (*first_char == '"') && (*(last_char-1) != '"'))
4334  {
4335  (void)sprintf(message, "Unpaired double quote in VALUE%s", element_prompt);
4336  status = OdlPrintMessage(message_fname,message_fptr, line_number, message);
4337  }
4338  else
4339  /* value is unquoted */
4340  if ((*first_char != '\'') && (*last_char != '\''))
4341  {
4342  /* check the value only if it isn't N/A */
4343  if ((strcmp(first_char, "n/a") != 0) && (strcmp(first_char, "N/A") != 0))
4344  {
4345  /* we can't have multiple underscores in an unquoted value */
4346  if (strstr(first_char, "__") != NULL)
4347  {
4348  (void)sprintf(message, "Multiple underscores in VALUE%s", element_prompt);
4349  status = OdlPrintMessage(message_fname,message_fptr, line_number, message);
4350  }
4351 
4352  /* an unquoted value cannot begin with an underscore */
4353  if (*first_char == '_')
4354  {
4355  (void)sprintf(message, "First character is an underscore in VALUE%s", element_prompt);
4356  status = OdlPrintMessage(message_fname,message_fptr, line_number, message);
4357  }
4358 
4359  /* an unquoted value cannot end with an underscore */
4360  if (*last_char == '_')
4361  {
4362  (void)sprintf(message, "Last character is an underscore in VALUE%s", element_prompt);
4363  status = OdlPrintMessage(message_fname,message_fptr, line_number, message);
4364  }
4365 
4366  /* the value may have a units expression */
4367  if ((units_start = (char *) strchr(text, (int) '<')) != NULL)
4368  {
4369  CopyString(save_units, units_start)
4370  *units_start = '\0';
4371  StripTrailing(text, ' ')
4372  }
4373 
4374  if (OdlDataType(text) == ODL_UNKNOWN)
4375  {
4376  (void)sprintf(message, "Unable to determine the data type of VALUE%s: \"%s\"",
4377  element_prompt, first_char);
4378  status = OdlPrintMessage(message_fname, message_fptr, line_number, message);
4379  }
4380 
4381  /* validate the units expression, if any */
4382  if (units_start != NULL)
4383  {
4384  /* only one '<' char allowed in a units expression */
4385  if (strchr(units_start+1, (int) '<') != NULL)
4386  {
4387  (void)sprintf(message, "Embedded '<' character found in the UNITS expression: \"<%s\", for VALUE%s: \"%s\"",
4388  units_start+1, element_prompt, first_char);
4389  status = OdlPrintMessage(message_fname, message_fptr, line_number, message);
4390  }
4391 
4392  /* find the closing char for the units expression */
4393  units_end = (char *) strchr(units_start+1, (int) '>');
4394 
4395  /* missing the closing '>' char in the units expression */
4396  if (units_end == NULL)
4397  {
4398  (void)sprintf(message, "Missing the closing '>' character in the UNITS expression: \"<%s\", for VALUE%s: \"%s\"",
4399  units_start+1, element_prompt, first_char);
4400  status = OdlPrintMessage(message_fname, message_fptr, line_number, message);
4401  }
4402  else
4403  /* characters found after the closing '>' in the units exp */
4404  if (units_end != last_char)
4405  {
4406  (void)sprintf(message, "Extraneous characters found after the closing '>' character in the UNITS expression: \"<%s\", for VALUE%s: \"%s\"",
4407  units_start+1, element_prompt, first_char);
4408  status = OdlPrintMessage(message_fname, message_fptr, line_number, message);
4409  }
4410 
4411  /* restore the value */
4412  (void)strcat(text, " ");
4413  (void)strcat(text, save_units);
4414  LemmeGo(save_units)
4415 
4416  } /* End: "if (units_start != NULL) ..." */
4417 
4418  } /* End: "if ((strcmp(first_char, "n/a") != 0) && ..." */
4419 
4420  } /* End: "if ((double_quote > ... else ... else ..." */
4421 
4422  LemmeGo(message)
4423 
4424  return(status);
4425 
4426 } /* End routine: "OdlValidElement" */
4427 
4428 
4429 /*******************/
4430 /* Local Routine */
4431 /*******************/
4432 
4433 #ifdef _NO_PROTO
4434 
4435 short OdlValidEndObjDesc (curr_object, equals, right_part,
4436  message_fname, message_fptr, line_number, group_type)
4437 OBJDESC *curr_object;
4438 char *equals;
4439 char *right_part;
4440 char *message_fname;
4441 FILE *message_fptr;
4442 long line_number;
4443 unsigned short group_type;
4444 
4445 #else
4446 
4447 short OdlValidEndObjDesc (OBJDESC *curr_object, char *equals,
4448  char *right_part, char *message_fname,
4449  FILE *message_fptr, long line_number, unsigned short group_type)
4450 
4451 #endif
4452 {
4453  short status = {TRUE};
4454  char errmsg[120];
4455 
4456  if (curr_object->parent == NULL)
4457  {
4458  /* Found an extra END_GROUP or END_OBJECT */
4459  (void)sprintf (errmsg,
4460  "Encountered an extra END_%s - Ignored",
4461  (group_type==ODL_OBJECT) ? "OBJECT" : "GROUP");
4462  status = OdlPrintMessage(message_fname, message_fptr, line_number, errmsg);
4463  }
4464 
4465  if (*equals != '\0')
4466  {
4467  if (curr_object->is_a_group == group_type)
4468  {
4469  /* Make sure that the name in the END_OBJECT or END_GROUP part
4470  matches the name that was given previously in the OBJECT
4471  or GROUP part */
4472 
4473  if (*right_part != '\0')
4474  {
4475  if (strcmp(curr_object->class, right_part) != 0)
4476  {
4477  (void)sprintf (errmsg,
4478  "END_%s = %s doesn't match %s = %s",
4479  (group_type==ODL_OBJECT) ? "OBJECT" : "GROUP",
4480  right_part,
4481  (curr_object->is_a_group==ODL_OBJECT) ? "OBJECT" : "GROUP",
4482  curr_object->class);
4483  status = OdlPrintMessage(message_fname, message_fptr, line_number, errmsg);
4484  }
4485  }
4486 
4487  status = OdlValidIdentifier(right_part, "END_OBJECT class",
4488  message_fname, message_fptr,line_number) && status;
4489  }
4490  else
4491  {
4492  /* Found an END_GROUP when expecting END_OBJECT, or vice versa */
4493 
4494  (void)sprintf (errmsg,
4495  "Found END_%s when expecting END_%s - Ignored",
4496  (group_type==ODL_OBJECT) ? "OBJECT" : "GROUP",
4497  (curr_object->is_a_group==ODL_OBJECT) ? "OBJECT" : "GROUP");
4498  status = OdlPrintMessage(message_fname, message_fptr, line_number, errmsg);
4499  }
4500 
4501  } /* End: "if (*equals != '\0') ..." */
4502 
4503  return(status);
4504 
4505 } /* End routine: "OdlValidEndObjDesc" */
4506 
4507 
4508 /*******************/
4509 /* Local Routine */
4510 /*******************/
4511 
4512 #ifdef _NO_PROTO
4513 
4514 short OdlValidIdentifier (id_name, id_type, message_fname, message_fptr, line_number)
4515 
4516 const char *id_name;
4517 const char *id_type;
4518 const char *message_fname;
4519 FILE *message_fptr;
4520 long line_number;
4521 
4522 #else
4523 
4524 short OdlValidIdentifier (const char *id_name, const char *id_type,
4525  const char *message_fname, FILE *message_fptr,
4526  long line_number)
4527 
4528 #endif
4529 {
4530  char *message = NULL;
4531  char *c = {NULL};
4532  int i;
4533  short status = {TRUE};
4534 
4535  NewString(message, (TB_MAXLINE+(long)strlen(id_name)+(long)strlen(id_type)))
4536 
4537  if (id_name == NULL)
4538  {
4539  (void)sprintf(message, "%s identifier is missing", id_type);
4540  status = OdlPrintMessage(message_fname, message_fptr, line_number,message);
4541  }
4542  else
4543  {
4544  char *local_id_name = strdup(id_name);
4545  if (!local_id_name)
4546  SayGoodbye();
4547 
4548  StripUnprintables(local_id_name)
4549 
4550  if (*local_id_name == '\0')
4551  {
4552  (void)sprintf(message, "%s identifier is missing", id_type);
4553  status = OdlPrintMessage(message_fname, message_fptr, line_number, message);
4554  }
4555  else
4556  {
4557  if (! isalpha(*local_id_name))
4558  {
4559  (void)sprintf(message,
4560  "%s identifier: \"%s\" does not begin with a letter",
4561  id_type, local_id_name);
4562  status = OdlPrintMessage(message_fname, message_fptr, line_number, message);
4563  }
4564 
4565  for (c=local_id_name,i=0; *c != '\0'; ++c)
4566  {
4567  if ((*c != '_') && (! isalnum(*c))) ++i;
4568  }
4569 
4570  if (i > 0)
4571  {
4572  (void)sprintf(message,
4573  "%s identifier: \"%s\" contains %d embedded non-alphanumeric or \"_\" character",
4574  id_type, id_name, i);
4575  if (i > 1) (void)strcat(message, "s");
4576  status = OdlPrintMessage(message_fname, message_fptr, line_number, message);
4577  }
4578 
4579  } /* End: "if (*id_name == '\0') ... else ..." */
4580 
4581  free(local_id_name);
4582  } /* End: "if (id_name == NULL) ... else ..." */
4583 
4584  LemmeGo(message)
4585 
4586  return(status);
4587 
4588 } /* End routine: "OdlValidIdentifier" */
4589 
4590 
4591 /*******************/
4592 /* Local Routine */
4593 /*******************/
4594 
4595 #ifdef _NO_PROTO
4596 
4597 short OdlValidKwd (curr_object, left_part, equals, right_part,
4598  message_fname, message_fptr, line_number)
4599 OBJDESC *curr_object;
4600 char *left_part;
4601 char *equals;
4602 char *right_part;
4603 char *message_fname;
4604 FILE *message_fptr;
4605 long line_number;
4606 
4607 #else
4608 
4609 short OdlValidKwd (OBJDESC *curr_object, char *left_part, char *equals,
4610  char *right_part, char *message_fname,
4611  FILE *message_fptr, long line_number)
4612 
4613 #endif
4614 {
4615  KEYWORD *keyword = {NULL};
4616  char *key = {NULL};
4617  char *message = NULL;
4618  short status = {TRUE};
4619  short sfdu_only = {FALSE};
4620  short found_keyword = {FALSE};
4621 
4622  NewString(message, (TB_MAXLINE+(long)strlen(left_part)+(long)strlen(right_part)))
4623 
4624  if (*left_part == '=')
4625  {
4626  *left_part = '\0';
4627  status = OdlPrintMessage(message_fname, message_fptr, line_number,
4628  "KEYWORD identifier is missing");
4629  }
4630  else
4631  {
4632  if (*equals == '\0')
4633  {
4634  sfdu_only = ((strncmp(left_part, "NJPL", 4) == 0) ||
4635  (strncmp(left_part, "CCSD", 4) == 0));
4636 
4637  if (! sfdu_only)
4638  {
4639  (void)sprintf(message,
4640  "Missing equals sign after KEYWORD identifier: \"%s\"", left_part);
4641  status = OdlPrintMessage(message_fname, message_fptr, line_number, message);
4642  }
4643  }
4644  else
4645  {
4646  *equals = '\0';
4647  StripTrailing(left_part, ' ')
4648  }
4649 
4650  /* ignore the first character if the keyword is a pointer */
4651  key = (*left_part != '^') ? left_part : left_part + 1;
4652 
4653  status = OdlValidIdentifier(key, "KEYWORD", message_fname,
4654  message_fptr, line_number) && status;
4655 
4656  for (keyword=curr_object->first_keyword;
4657  ((keyword != NULL) && (! found_keyword));
4658  keyword=keyword->right_sibling)
4659  {
4660  if (keyword->name != NULL)
4661  found_keyword = (strcmp(keyword->name, left_part) == 0);
4662  }
4663 
4664  if (found_keyword)
4665  {
4666  (void)sprintf(message,
4667  "Duplicate KEYWORD identifier: \"%s\"", left_part);
4668  status = OdlPrintMessage(message_fname, message_fptr, line_number,message);
4669  }
4670 
4671  } /* End: "if (*left_part == '=') ... else ..." */
4672 
4673  if (*right_part != '\0')
4674  {
4675  /* what sort of value do we have? */
4676  if ((*right_part != '{') && (*right_part != '('))
4677  {
4678  /* we have a single element */
4679  status = OdlValidElement(right_part, message_fname, message_fptr,
4680  line_number, (long)0) && status;
4681  }
4682  else
4683  {
4684  /* we have a value list */
4685  status = OdlValidValueList(right_part, message_fname, message_fptr,
4686  line_number) && status;
4687  }
4688  }
4689  else
4690  if (! sfdu_only)
4691  {
4692  (void)sprintf(message,
4693  "KEYWORD identifier: \"%s\" is missing a VALUE",
4694  left_part);
4695  status = OdlPrintMessage(message_fname, message_fptr, line_number,message);
4696  }
4697 
4698  LemmeGo(message)
4699 
4700  return(status);
4701 
4702 } /* End routine: "OdlValidKwd" */
4703 
4704 
4705 /*******************/
4706 /* Local Routine */
4707 /*******************/
4708 
4709 #ifdef _NO_PROTO
4710 
4711 short OdlValidObjDesc (curr_object, equals, right_part,
4712  message_fname, message_fptr, line_number)
4713 
4714 OBJDESC *curr_object;
4715 char *equals;
4716 char *right_part;
4717 char *message_fname;
4718 FILE *message_fptr;
4719 long line_number;
4720 
4721 #else
4722 
4723 short OdlValidObjDesc (OBJDESC *curr_object, char *equals,
4724  char *right_part, char *message_fname,
4725  FILE *message_fptr, long line_number)
4726 
4727 #endif
4728 {
4729  short status = {TRUE};
4730 
4731  if (*equals == '\0')
4732  {
4733  status = OdlPrintMessage(message_fname, message_fptr, line_number,
4734  "Missing equals sign after OBJECT statement");
4735  }
4736 
4737  StripTrailing(right_part, ' ')
4738 
4739  status = OdlValidIdentifier(right_part, "OBJECT class",
4740  message_fname, message_fptr,line_number) && status;
4741 
4742  return(status);
4743 
4744 } /* End routine: "OdlValidObjDesc" */
4745 
4746 
4747 
4748 /*******************/
4749 /* Local Routine */
4750 /*******************/
4751 
4752 #ifdef _NO_PROTO
4753 
4754 short OdlValidValueList (text, message_fname, message_fptr, line_number)
4755 
4756 char *text;
4757 char *message_fname;
4758 FILE *message_fptr;
4759 long line_number;
4760 
4761 #else
4762 
4763 short OdlValidValueList (char *text, char *message_fname,
4764  FILE *message_fptr, long line_number)
4765 
4766 #endif
4767 {
4768  char *first_char = {NULL};
4769  char *last_char = {NULL};
4770  char save_c;
4771  long i;
4772  short status = {TRUE};
4773 
4774  for (i=1,first_char=OdlValueStart(text); *first_char != '\0'; ++i)
4775  {
4776  /* find the end of the current element */
4777  last_char = OdlValueEnd(first_char);
4778 
4779  /* save the next character and terminate the string */
4780  save_c = *(++last_char);
4781  *last_char = '\0';
4782 
4783  /* validate the current element */
4784  (void)OdlValidElement(first_char,message_fname,message_fptr,line_number,i);
4785 
4786  /* restore the character that was overwritten by the terminator */
4787  *last_char = save_c;
4788 
4789  /* find the start of the next element */
4790  first_char = OdlValueStart(last_char);
4791 
4792  } /* End: "for (i=1, ..." */
4793 
4794  return(status);
4795 
4796 } /* End routine: "OdlValidValueList" */
4797 
4798 
4799 
4800 
4801 /*========================================================================*/
4802 /* */
4803 /* Miscellaneous routines */
4804 /* */
4805 /*========================================================================*/
4806 
4807 
4808 /************************************************************************/
4809 /* */
4810 /* Component: */
4811 /* */
4812 /* OdlWildCardCompare */
4813 /* */
4814 /* Author: */
4815 /* */
4816 /* David P. Bernath (Jet Propulsion Laboratory) */
4817 /* */
4818 /* Version: */
4819 /* */
4820 /* 1.0 March 31, 1994 */
4821 /* */
4822 /* Change History: */
4823 /* */
4824 /* 03-31-94 Original code */
4825 /* */
4826 /*----------------------------------------------------------------------*/
4827 /* */
4828 /* Description: */
4829 /* */
4830 /* This routine compares two text strings, one of which may have */
4831 /* wildcard characters in it ('*'). */
4832 /* */
4833 /************************************************************************/
4834 
4835 #ifdef _NO_PROTO
4836 
4837 unsigned short OdlWildCardCompare (wildcard_text, plain_text)
4838 
4839 const char *wildcard_text;
4840 const char *plain_text;
4841 
4842 #else
4843 
4844 unsigned short OdlWildCardCompare (const char *wildcard_text,
4845  const char *plain_text)
4846 
4847 #endif
4848 {
4849  char *c = {NULL};
4850  char *substr = {NULL};
4851  char *tmp_str = {NULL};
4852  char *tmp_str2 = {NULL};
4853  char *text_start = {NULL};
4854  char save_it;
4855  unsigned long len;
4856  unsigned short allrightythen = {FALSE};
4857  int StartOfLine = 1;
4858 
4859  /* see if we have anything to compare */
4860  if ((wildcard_text != NULL) && (plain_text != NULL))
4861  {
4862  /* all righty then, let's initialize some local variables */
4863  allrightythen = TRUE;
4864 
4865  /* copy the wildcard text */
4866  CopyString(tmp_str, wildcard_text)
4867 
4868  /* strip off leading and trailing quotes */
4869  save_it = *tmp_str;
4870  if ((save_it == '\'') || (save_it == '"'))
4871  {
4872  StripLeading(tmp_str, save_it)
4873  StripTrailing(tmp_str, save_it)
4874  StripLeading(tmp_str, ' ')
4875  StripTrailing(tmp_str, ' ')
4876  }
4877 
4878  /* copy the plain text */
4879  CopyString(tmp_str2, plain_text)
4880 
4881  /* strip off leading and trailing quotes */
4882  save_it = *tmp_str2;
4883  if ((save_it == '\'') || (save_it == '"'))
4884  {
4885  StripLeading(tmp_str2, save_it)
4886  StripTrailing(tmp_str2, save_it)
4887  StripLeading(tmp_str2, ' ')
4888  StripTrailing(tmp_str2, ' ')
4889  }
4890 
4891  substr = tmp_str;
4892  /* if * is in the front of the substr, then don't check to see the the front of the substr and text_start match */
4893  if (*substr == '*')
4894  {
4895  StartOfLine = 0;
4896  }
4897  text_start = tmp_str2;
4898 
4899  if (strchr(substr, '*') == NULL)
4900  allrightythen = (strcmp(text_start, substr) == 0);
4901  else
4902  {
4903 
4904  /* we're going to break out the chunks of text between the */
4905  /* wildcard caracters and try to find them one-by-one in */
4906  /* the plain text string. */
4907  for(;;)
4908  {
4909  /* locate the start of next substring */
4910  for ( ; *substr == '*'; ++substr) ;
4911  if (*substr == '\0') break;
4912 
4913  /* locate the end of the substring and save that address */
4914  for (c=substr; ((*c != '*') && (*c != '\0')); ++c) ;
4915  save_it = *c;
4916  *c = '\0';
4917 
4918  /* look for the substring in the un-wildcarded text */
4919  if ((c = (char *)strstr(text_start, substr)) == NULL)
4920  {
4921  allrightythen = FALSE;
4922  break;
4923  }
4924  else if (StartOfLine)
4925  {
4926  if (c != text_start)
4927  {
4928  allrightythen = FALSE;
4929  break;
4930  }
4931  StartOfLine = 0;
4932  }
4933 
4934  /* prepare for the next search */
4935  len = strlen(substr);
4936  substr += len;
4937  *substr = save_it;
4938  text_start = c + len;
4939  if ((*substr == '\0') && (*text_start != '\0'))
4940  {
4941  allrightythen = FALSE;
4942  break;
4943  }
4944 
4945  }
4946 
4947  } /* End: "if (strchr(substr, '*') == NULL) ... else ..." */
4948 
4949  LemmeGo(tmp_str)
4950  LemmeGo(tmp_str2)
4951 
4952  } /* End: "if ((wildcard_text != NULL) && ..." */
4953 
4954  return(allrightythen);
4955 
4956 } /* End: "OdlWildCardCompare" */
4957 
4958 
4959 
4960 
4961 /************************************************************************/
4962 /* */
4963 /* Component: */
4964 /* */
4965 /* OdlTraverseTree */
4966 /* */
4967 /* Author: */
4968 /* */
4969 /* David P. Bernath (Jet Propulsion Laboratory) */
4970 /* */
4971 /* Version: */
4972 /* */
4973 /* 1.0 March 31, 1994 */
4974 /* */
4975 /* Change History: */
4976 /* */
4977 /* 03-31-94 Original code */
4978 /* */
4979 /*----------------------------------------------------------------------*/
4980 /* */
4981 /* Description: */
4982 /* */
4983 /* This routine locates the next object in an ODL tree, stopping */
4984 /* when it has traversed the entire tree as defined by the */
4985 /* root_level parameter. */
4986 /* */
4987 /************************************************************************/
4988 
4989 #ifdef _NO_PROTO
4990 
4991 OBJDESC *OdlTraverseTree (curr_object, root_level)
4992 
4993 OBJDESC *curr_object;
4994 unsigned long root_level;
4995 
4996 #else
4997 
4998 OBJDESC *OdlTraverseTree (OBJDESC *curr_object, unsigned long root_level)
4999 
5000 #endif
5001 {
5002  OBJDESC *obj = {NULL};
5003  OBJDESC *next_object = {NULL};
5004 
5005  if (curr_object != NULL)
5006  {
5007  /* start search with current object's children */
5008  if (curr_object->first_child != NULL)
5009  next_object = curr_object->first_child;
5010  else
5011  /* start search with current object's right sibling */
5012  if (curr_object->right_sibling != NULL)
5013  next_object = curr_object->right_sibling;
5014  else
5015  /* move up parent list until we find one with a right sibling */
5016  {
5017  for (next_object=NULL,obj=curr_object->parent;
5018  (obj != NULL); obj=obj->parent)
5019  {
5020  if (obj->level <= root_level)
5021  break;
5022  else
5023  if (obj->right_sibling != NULL)
5024  {
5025  next_object = obj->right_sibling;
5026  break;
5027  }
5028  }
5029 
5030  } /* End: "if (curr_object->first_child ... else ..." */
5031 
5032  } /* End: "if (curr_object != NULL) ..." */
5033 
5034  return(next_object);
5035 
5036 } /* End routine: "OdlTraverseTree" */
5037 
5038 
5039 
5040 /************************************************************************/
5041 /* */
5042 /* Component: */
5043 /* */
5044 /* OdlFirstWord */
5045 /* */
5046 /* Author: */
5047 /* */
5048 /* David P. Bernath (Jet Propulsion Laboratory) */
5049 /* */
5050 /* Version: */
5051 /* */
5052 /* 1.0 March 31, 1994 */
5053 /* */
5054 /* Change History: */
5055 /* */
5056 /* 03-31-94 Original code */
5057 /* */
5058 /*----------------------------------------------------------------------*/
5059 /* */
5060 /* Description: */
5061 /* */
5062 /* This routine returns a pointer to the first word in a string */
5063 /* of text. A word is anything that begins with a printable */
5064 /* ASCII character. */
5065 /* */
5066 /************************************************************************/
5067 
5068 #ifdef _NO_PROTO
5069 
5070 char *OdlFirstWord(text)
5071 
5072 char *text;
5073 
5074 #else
5075 
5076 char *OdlFirstWord(char *text)
5077 
5078 #endif
5079 {
5080  char *c = {NULL};
5081  for (c=text;
5082  ((c != NULL) && ((*c <= ' ') || (*c > '~')) && (*c != '\0')); ++c) ;
5083  return(c);
5084 
5085 } /* End routine: "OdlFirstWord" */
5086 
5087 
5088 
5089 /************************************************************************/
5090 /* */
5091 /* Component: */
5092 /* */
5093 /* OdlNextWord */
5094 /* */
5095 /* Author: */
5096 /* */
5097 /* David P. Bernath (Jet Propulsion Laboratory) */
5098 /* */
5099 /* Version: */
5100 /* */
5101 /* 1.0 March 31, 1994 */
5102 /* */
5103 /* Change History: */
5104 /* */
5105 /* 03-31-94 Original code */
5106 /* */
5107 /*----------------------------------------------------------------------*/
5108 /* */
5109 /* Description: */
5110 /* */
5111 /* This routine locates the next word in a string of text. It */
5112 /* locates the end of the current word and skips over whitespace */
5113 /* to find the start of the next. A word is anything that begins */
5114 /* with a printable ASCII character. */
5115 /* */
5116 /************************************************************************/
5117 
5118 #ifdef _NO_PROTO
5119 
5120 char *OdlNextWord(text)
5121 
5122 char *text;
5123 
5124 #else
5125 
5126 char *OdlNextWord( char *text)
5127 
5128 #endif
5129 {
5130  char *c = {NULL};
5131  for (c=text;
5132  ((c != NULL) && (*c > ' ') && (*c <= '~') && (*c != '\0')); ++c) ;
5133  return(OdlFirstWord(c));
5134 
5135 } /* End routine: "OdlNextWord" */
5136 
5137 
5138 /************************************************************************/
5139 /* */
5140 /* Component: */
5141 /* */
5142 /* OdlValueStart */
5143 /* */
5144 /* Author: */
5145 /* */
5146 /* David P. Bernath (Jet Propulsion Laboratory) */
5147 /* */
5148 /* Version: */
5149 /* */
5150 /* 1.0 March 31, 1994 */
5151 /* */
5152 /* Change History: */
5153 /* */
5154 /* 03-31-94 Original code */
5155 /* */
5156 /*----------------------------------------------------------------------*/
5157 /* */
5158 /* Description: */
5159 /* */
5160 /* This routine locates the start of a value within a set or */
5161 /* sequence. A value is anything that doesn't begin with a brace, */
5162 /* comma, paren, or blank. */
5163 /* */
5164 /************************************************************************/
5165 
5166 #ifdef _NO_PROTO
5167 
5168 char *OdlValueStart(text)
5169 
5170 char *text;
5171 
5172 #else
5173 
5174 char *OdlValueStart(char *text)
5175 
5176 #endif
5177 {
5178  /* find a character that is not a brace, paren, comma, or blank */
5179  return(text + strspn(text, "{}(), \n"));
5180 
5181 } /* End routine: "OdlValueStart" */
5182 
5183 
5184 /************************************************************************/
5185 /* */
5186 /* Component: */
5187 /* */
5188 /* OdlValueEnd */
5189 /* */
5190 /* Author: */
5191 /* */
5192 /* David P. Bernath (Jet Propulsion Laboratory) */
5193 /* */
5194 /* Version: */
5195 /* */
5196 /* 1.0 March 31, 1994 */
5197 /* */
5198 /* Change History: */
5199 /* */
5200 /* 03-31-94 Original code */
5201 /* */
5202 /*----------------------------------------------------------------------*/
5203 /* */
5204 /* Description: */
5205 /* */
5206 /* This routine finds the end of a value within a set or sequence. */
5207 /* A value is anything that doesn't begin with a brace, comma, */
5208 /* paren, or blank. It finds the end by locating a comma, paren, */
5209 /* or brace, and backing up over trailing whitespace. */
5210 /* */
5211 /************************************************************************/
5212 
5213 #ifdef _NO_PROTO
5214 
5215 char *OdlValueEnd(text)
5216 
5217 char *text;
5218 
5219 #else
5220 
5221 char *OdlValueEnd( char *text)
5222 
5223 #endif
5224 {
5225  char *c = {NULL};
5226 
5227  /* find a character that is a brace, paren, or comma */
5228  c = strpbrk(text, "{}(),");
5229 
5230  /* backup over any trailing blanks */
5231  for (--c; ((c > text) && ((*c == ' ') || (*c == '\0'))); --c) ;
5232 
5233  return(c);
5234 
5235 } /* End routine: "OdlValueEnd" */
5236 
5237 
5238 
5239 /************************************************************************/
5240 /* */
5241 /* Component: */
5242 /* */
5243 /* OdlValueRowStart */
5244 /* */
5245 /* Author: */
5246 /* */
5247 /* David P. Bernath (Jet Propulsion Laboratory) */
5248 /* */
5249 /* Version: */
5250 /* */
5251 /* 1.0 March 31, 1994 */
5252 /* */
5253 /* Change History: */
5254 /* */
5255 /* 03-31-94 Original code */
5256 /* */
5257 /*----------------------------------------------------------------------*/
5258 /* */
5259 /* Description: */
5260 /* */
5261 /* This routine locates the start of a set or sequence within a */
5262 /* set or sequence. A set begins with a brace and a sequence */
5263 /* begins with a paren. */
5264 /* */
5265 /************************************************************************/
5266 
5267 #ifdef _NO_PROTO
5268 
5269 char *OdlValueRowStart(text)
5270 char *text;
5271 
5272 #else
5273 
5274 char *OdlValueRowStart( char *text)
5275 
5276 #endif
5277 {
5278  /* find a character that is not a brace or paren */
5279  return(text + strspn(text, "{}()\n"));
5280 
5281 } /* End routine: "OdlValueRowStart" */
5282 
5283 
5284 /************************************************************************/
5285 /* */
5286 /* Component: */
5287 /* */
5288 /* OdlValueRowEnd */
5289 /* */
5290 /* Author: */
5291 /* */
5292 /* David P. Bernath (Jet Propulsion Laboratory) */
5293 /* */
5294 /* Version: */
5295 /* */
5296 /* 1.0 March 31, 1994 */
5297 /* */
5298 /* Change History: */
5299 /* */
5300 /* 03-31-94 Original code */
5301 /* */
5302 /*----------------------------------------------------------------------*/
5303 /* */
5304 /* Description: */
5305 /* */
5306 /* This routine locates the end of a set or sequence within a */
5307 /* set or sequence. A set begins with a brace and a sequence */
5308 /* begins with a paren. It finds a closing brace or paren and */
5309 /* backs up over any whitespace. */
5310 /* */
5311 /************************************************************************/
5312 
5313 #ifdef _NO_PROTO
5314 
5315 char *OdlValueRowEnd(text)
5316 char *text;
5317 
5318 #else
5319 
5320 char *OdlValueRowEnd( char *text)
5321 
5322 #endif
5323 {
5324  char *c = {NULL};
5325 
5326  /* find a character that is a brace or paren */
5327  c = strpbrk(text, "{}()\n");
5328 
5329  /* backup over any trailing blanks or commas */
5330  for (--c; ((c > text) && ((*c == ' ') || (*c == ',') || (*c == '\0'))); --c) ;
5331 
5332  return(c);
5333 
5334 } /* End routine: "OdlValueRowEnd" */
5335 
5336 
5337 
5338 /************************************************************************/
5339 /* */
5340 /* Component: */
5341 /* */
5342 /* OdlDataType */
5343 /* */
5344 /* Author: */
5345 /* */
5346 /* David P. Bernath (Jet Propulsion Laboratory) */
5347 /* */
5348 /* Version: */
5349 /* */
5350 /* 1.0 March 31, 1994 */
5351 /* */
5352 /* Change History: */
5353 /* */
5354 /* 03-31-94 Original code */
5355 /* 04-09-97 Added Landsat 7 Date and Time */
5356 /* */
5357 /*----------------------------------------------------------------------*/
5358 /* */
5359 /* Description: */
5360 /* */
5361 /* This routine determines the ODL data type of a text string. */
5362 /* */
5363 /************************************************************************/
5364 
5365 #ifdef _NO_PROTO
5366 
5367 unsigned short OdlDataType (text)
5368 
5369 char *text;
5370 
5371 #else
5372 
5373 unsigned short OdlDataType (char *text)
5374 
5375 #endif
5376 {
5377  char *c = {NULL};
5378  char *u = {NULL};
5379  char *tempstr = {NULL};
5380  char *last_pound = {NULL};
5381  int base;
5382  unsigned long decimal_count = {0};
5383  unsigned long hyphen_count = {0};
5384  unsigned long colon_count = {0};
5385  unsigned long t_count = {0};
5386  unsigned short has_sign = {FALSE};
5387  unsigned short type = {ODL_UNKNOWN};
5388  unsigned short exponent_type = {ODL_UNKNOWN};
5389  static const char *valid_chars[17] = {
5390  "", /* base 0 */
5391  "0", /* base 1 */
5392  "01", /* base 2 */
5393  "012", /* base 3 */
5394  "0123", /* base 4 */
5395  "01234", /* base 5 */
5396  "012345", /* base 6 */
5397  "0123456", /* base 7 */
5398  "01234567", /* base 8 */
5399  "012345678", /* base 9 */
5400  "0123456789", /* base 10 */
5401  "0123456789A", /* base 11 */
5402  "0123456789AB", /* base 12 */
5403  "0123456789ABC", /* base 13 */
5404  "0123456789ABCD", /* base 14 */
5405  "0123456789ABCDE", /* base 15 */
5406  "0123456789ABCDEF"}; /* base 16 */
5407 
5408  if (text != NULL)
5409  {
5410  /* make a copy of the string */
5411  CopyString(tempstr, text)
5412 
5413  /* remove any units */
5414  if ((u = (char *)strchr(tempstr, '<')) != NULL) *u = '\0';
5415 
5416  /* clean up blanks and convert to upper case */
5417  StripLeading(tempstr, ' ')
5418  StripTrailing(tempstr, ' ')
5419  UpperCase(tempstr)
5420 
5421  c = tempstr;
5422 
5423  type = ODL_SYMBOL;
5424 
5425  /* See if we have a double quoted text value */
5426  if (*c == '"')
5427  type = ODL_TEXT;
5428  else
5429  /* See if we have a single quoted text value */
5430  if (*c == '\'')
5431  type = ODL_SYMBOL;
5432  else
5433  /* See if we have a sequence of values */
5434  if (*c == '{')
5435  type = ODL_SEQUENCE;
5436  else
5437  /* See if we have a set of values */
5438  if (*c == '(')
5439  type = ODL_SET;
5440  else
5441  /* See if we have any embedded blanks */
5442  if (strchr(c, ' ') != NULL)
5443  type = ODL_UNKNOWN;
5444  else
5445  /* See if we have an integer, real, date, or date-time value */
5446  {
5447  /* we're going to check each character */
5448  for ( ; *c != '\0'; ++c)
5449  {
5450  /* may have a number */
5451  if (isdigit(*c))
5452  {
5453  if (c == tempstr)
5454  type = ODL_INTEGER;
5455  else
5456  if (has_sign && (c == (tempstr + 1)))
5457  type = ODL_INTEGER;
5458  }
5459  else
5460  /* we may have a real number or a date-time */
5461  if (*c == '.')
5462  {
5463  /* we may have a real number */
5464  if (type == ODL_INTEGER)
5465  type = ODL_REAL;
5466  else
5467  /* date-times can only have one decimal point */
5468  if ( (type == ODL_DATE_TIME) || (type == ODL_L7_DATE_TIME_FRAC) )
5469  {
5470  if ((++decimal_count) > 1)
5471  type = ODL_UNKNOWN;
5472  }
5473  else
5474  /* Landsat 7 date and time fraction */
5475  if (type == ODL_L7_DATE_TIME)
5477  else
5478  /* we may have a real number */
5479  if (c == tempstr)
5480  type = ODL_REAL;
5481  else
5482  /* we may have a signed real number */
5483  if (has_sign && (c == (tempstr + 1)))
5484  type = ODL_REAL;
5485  else
5486  type = ODL_UNKNOWN;
5487  }
5488  else
5489  /* we may have a real number in scientific notation */
5490  if (*c == 'E')
5491  {
5492  /* only valid if we thought we had an int or real */
5493  if ((type == ODL_INTEGER) || (type == ODL_REAL))
5494  {
5495  /* check out the exponent */
5496  exponent_type = (unsigned short) OdlDataType((c+1));
5497 
5498  /* we have a real number only if the exponent */
5499  /* is real or int */
5500  if ((exponent_type == ODL_REAL) || (exponent_type == ODL_INTEGER))
5501  type = ODL_REAL;
5502  else
5503  type = ODL_UNKNOWN;
5504 
5505  break;
5506  }
5507  else
5508  if (type != ODL_SYMBOL)
5509  type = ODL_UNKNOWN;
5510  }
5511  else
5512  /* we may have a signed number */
5513  if (*c == '+')
5514  {
5515  /* this had better be the first character */
5516  if (c != tempstr)
5517  type = ODL_UNKNOWN;
5518  else
5519  has_sign = TRUE;
5520  }
5521  else
5522  /* we may have a date or a signed number */
5523  if (*c == '-')
5524  {
5525  /* this had better be the first character */
5526  if (c == tempstr)
5527  has_sign = TRUE;
5528  else
5529  /* a date can have at most two hyphens */
5530  if ((++hyphen_count) > 2)
5531  type = ODL_UNKNOWN;
5532  else
5533  /* we thought we had an integer */
5534  if (type == ODL_INTEGER)
5535  type = ODL_DATE;
5536  else
5537  /* if it wasn't an int and it wasn't a date ... */
5538  if (type != ODL_DATE)
5539  type = ODL_UNKNOWN;
5540  }
5541  else
5542  /* we may have a date-time */
5543  if (*c == 'T')
5544  {
5545  /* we thought we had a date */
5546  if (type == ODL_DATE)
5547  type = ODL_DATE_TIME;
5548  else
5549  /* a date-time may only have one 'T' */
5550  if (type == ODL_DATE_TIME)
5551  {
5552  if ((++t_count) > 1)
5553  type = ODL_UNKNOWN;
5554  }
5555  else
5556  /* must be a symbol */
5557  if (type != ODL_SYMBOL)
5558  type = ODL_UNKNOWN;
5559  }
5560  else
5561  /* we may have a date-time */
5562  if (*c == 'Z')
5563  {
5564  /* only a date time may contain a 'Z' */
5565  if (type == ODL_DATE_TIME)
5566  {
5567  /* it had better be the last char in the string */
5568  if (*(c + 1) != '\0')
5569  type = ODL_UNKNOWN;
5570  }
5571  else
5572  if (type != ODL_SYMBOL)
5573  type = ODL_UNKNOWN;
5574  }
5575  else
5576  /* we may have a date-time */
5577  if (*c == ':')
5578  {
5579  /* we have a Landsat 7 date and time */
5580  if (type == ODL_INTEGER)
5582  /* only a date-time may contain colons */
5583  if ( (type != ODL_DATE_TIME) && (type != ODL_L7_DATE_TIME) )
5584  type = ODL_UNKNOWN;
5585  else
5586  /* there can't be more than two of them in date */
5587  if ( ((++colon_count) > 2) && (type != ODL_L7_DATE_TIME ) )
5588  type = ODL_UNKNOWN;
5589  else
5590  if ( ( colon_count > 4 ) && (type == ODL_L7_DATE_TIME) )
5591  type = ODL_UNKNOWN;
5592  else
5593  /* characters on either side must be digits */
5594  if ((! isdigit(*(c-1))) || (! isdigit(*(c+1))))
5595  type = ODL_UNKNOWN;
5596  else
5597  /* decimal points can't occur before the last colon */
5598  if (decimal_count != 0)
5599  type = ODL_UNKNOWN;
5600  }
5601  else
5602  /* we may have a non-decimal integer */
5603  if (*c == '#')
5604  {
5605  /* we didn't think it WAS an integer */
5606  if (type != ODL_INTEGER)
5607  type = ODL_UNKNOWN;
5608  else
5609  /* the base can't be signed */
5610  if (has_sign)
5611  type = ODL_UNKNOWN;
5612  else
5613  /* missing the closing '#' character */
5614  if ((last_pound = (char *)strchr(c+1, '#')) == NULL)
5615  type = ODL_UNKNOWN;
5616  else
5617  /* closing '#' char is not at the end */
5618  if (*(last_pound + 1) != '\0')
5619  type = ODL_UNKNOWN;
5620  else
5621  {
5622  /* looks good so far, but we have to make sure */
5623  /* stuff between the '#' characters is valid */
5624  /* with the specified base */
5625 
5626  /* isolate the base */
5627  *c = '\0';
5628  base = atoi(tempstr);
5629 
5630  /* ignore the integer's sign */
5631  ++c;
5632  if ((*c == '+') || (*c == '-')) ++c;
5633 
5634  /* isolate the number part */
5635  *last_pound = '\0';
5636 
5637  /* valid bases are 2 through 16, inclusive */
5638  if ((base < 2) || (base > 16))
5639  type = ODL_UNKNOWN;
5640  else
5641  /* look for invalid digits for the specified base */
5642  if (c[strspn(c, valid_chars[base])] != '\0')
5643  type = ODL_UNKNOWN;
5644  }
5645 
5646  if (type != ODL_UNKNOWN)
5647  {
5648  type = ODL_INTEGER;
5649  break;
5650  }
5651  }
5652  else
5653  /* we may have an unquoted symbol */
5654  if (isalpha(*c) || (*c == '_'))
5655  {
5656  if (type != ODL_SYMBOL)
5657  type = ODL_UNKNOWN;
5658  }
5659  else
5660  /* we havn't got a clue */
5661  type = ODL_UNKNOWN;
5662 
5663  if (type == ODL_UNKNOWN) break;
5664 
5665  } /* End: "for ( ; ..." */
5666 
5667  if (has_sign && (type != ODL_INTEGER) && (type != ODL_REAL))
5668  type = ODL_UNKNOWN;
5669 
5670  } /* End: "if (*c == '(') ... else ..." */
5671 
5672  LemmeGo(tempstr)
5673 
5674  } /* End: "if (text != NULL) ..." */
5675 
5676  return(type);
5677 
5678 } /* End: "OdlDataType" */
5679 
5680 /************************************************************************/
5681 /* */
5682 /* Component: */
5683 /* */
5684 /* OdlTypeString */
5685 /* */
5686 /* Author: */
5687 /* */
5688 /* David P. Bernath (Jet Propulsion Laboratory) */
5689 /* */
5690 /* Version: */
5691 /* */
5692 /* 1.0 March 31, 1994 */
5693 /* */
5694 /* Change History: */
5695 /* */
5696 /* 03-31-94 Original code */
5697 /* */
5698 /*----------------------------------------------------------------------*/
5699 /* */
5700 /* Description: */
5701 /* */
5702 /* This routine determines the ODL data type of a text string. */
5703 /* */
5704 /************************************************************************/
5705 
5706 #ifdef _NO_PROTO
5707 
5708 char *OdlTypeString (type, type_string)
5709 
5710 unsigned short type;
5711 char *type_string;
5712 
5713 #else
5714 
5715 char *OdlTypeString (unsigned short type, char *type_string)
5716 
5717 #endif
5718 {
5719  static char local_type_string [TB_MAXLINE];
5720 
5721  switch (type)
5722  {
5723  case ODL_INTEGER : (void)strcpy(local_type_string, "INTEGER");
5724  break;
5725 
5726  case ODL_REAL : (void)strcpy(local_type_string, "REAL");
5727  break;
5728 
5729  case ODL_SYMBOL : (void)strcpy(local_type_string, "SYMBOL");
5730  break;
5731 
5732  case ODL_TEXT : (void)strcpy(local_type_string, "TEXT");
5733  break;
5734 
5735  case ODL_DATE : (void)strcpy(local_type_string, "DATE");
5736  break;
5737 
5738  case ODL_DATE_TIME : (void)strcpy(local_type_string, "DATE-TIME");
5739  break;
5740 
5741  case ODL_SEQUENCE : (void)strcpy(local_type_string, "SEQUENCE");
5742  break;
5743 
5744  case ODL_SET : (void)strcpy(local_type_string, "SET");
5745  break;
5746 
5747  default : (void)strcpy(local_type_string, "UNKNOWN");
5748  break;
5749 
5750  } /* End: "switch (type) ..." */
5751 
5752  if (type_string != NULL) (void)strcpy(type_string, local_type_string);
5753 
5754  return(local_type_string);
5755 
5756 } /* End: "OdlTypeString" */
5757 
5758 
5759 
5760 /************************************************************************/
5761 /* */
5762 /* Component: */
5763 /* */
5764 /* OdlTempFname */
5765 /* */
5766 /* Author: */
5767 /* */
5768 /* David P. Bernath (Jet Propulsion Laboratory) */
5769 /* */
5770 /* Version: */
5771 /* */
5772 /* 1.0 March 31, 1994 */
5773 /* */
5774 /* Change History: */
5775 /* */
5776 /* 03-31-94 Original code */
5777 /* */
5778 /*----------------------------------------------------------------------*/
5779 /* */
5780 /* Description: */
5781 /* */
5782 /* This routine returns a unique file name, depending on the */
5783 /* system on which the code was compiled. */
5784 /* */
5785 /************************************************************************/
5786 
5788 {
5789  FILE *fptr = {NULL};
5790  char *fname = {NULL};
5791  char base_name [TB_MAXPATH + TB_MAXFNAME];
5792 
5793  (void)strcpy(base_name, "tmp.tmp");
5794 
5795 #ifdef SUN_UNIX
5796  (void)tmpnam(temp_str);
5797  (void)strcpy( base_name, temp_str); /* Bug fix 11/2/94 SM */
5798  /* Was: (void)sprintf(base_name, "~/%s.tmp", */
5799  /* temp_str); */
5800 #endif
5801 
5802 #if (defined( VAX) || defined( ALPHA_VMS))
5803  (void)tmpnam(temp_str);
5804  (void)sprintf(base_name, "sys$login:%s.tmp", temp_str);
5805 #endif
5806 
5807 #ifdef MAC_THINK
5808  (void)tmpnam(temp_str);
5809  (void)sprintf(base_name, "%s.tmp", temp_str);
5810 #endif
5811 
5812 #ifdef MSDOS
5813  {
5814  time_t t;
5815  t = (time_t) time(NULL);
5816  (void)sprintf(base_name, "C:\\%ld", t);
5817  base_name[8] = EOS;
5818  (void)strcat(base_name, ".tmp");
5819  }
5820 #endif
5821 
5822  CopyString(fname, base_name)
5823 
5824  if ((fptr = (FILE *) fopen(fname, "w")) == NULL)
5825  LemmeGo(fname)
5826  else
5827  CloseMe(fptr)
5828 
5829  return(fname);
5830 
5831 } /* End: "OdlTempFname" */
5832 
5833 
5834 short CheckBalance(text)
5835 char *text;
5836 {
5837  long quote_nesting = 0;
5838  long brace_nesting = 0;
5839  long paren_nesting = 0;
5840  char *c = {NULL};
5841  char *c1 = {NULL};
5842 
5843  c1 = (char *) strchr(text, '=');
5844  c = OdlFirstWord(c1 + 1);
5845 
5846  if ((*c == '(') || (*c == '{'))
5847  (void)OdlNestingLevel(c,&brace_nesting,&paren_nesting);
5848  else
5849  if (*c == '"')
5850  {
5851  for (; *c != '\0'; ++c)
5852  {
5853  if (*c == '"')
5854  {
5855  if (quote_nesting == 0)
5856  quote_nesting = 1;
5857  else
5858  quote_nesting = 0;
5859  }
5860  }
5861  }
5862 
5863  return((brace_nesting + paren_nesting + quote_nesting) == 0);
5864 }
5865 
5866 /*========================================================================*/
5867 /* */
5868 /* End of lablib 3.0 stuff */
5869 /* */
5870 /*========================================================================*/
5871 
#define ODL_L7_DATE_TIME
Definition: lablib3.h:61
int32 value
Definition: Granule.c:1235
data_t t[NROOTS+1]
Definition: decode_rs.h:77
OBJDESC * OdlNextObjDesc(OBJDESC *object, unsigned long root_level, unsigned short *search_scope)
Definition: lablib3.c:619
#define LemmeGo(zmptrz)
Definition: oli_toolbox.h:57
FILE * OdlLocateStart(char *filespec, unsigned long start_location, unsigned short start_location_type)
Definition: lablib3.c:2972
void OdlPrintLabel(OBJDESC *object, char *message_fname, FILE *message_fptr, unsigned long root_level)
Definition: lablib3.c:3463
KEYWORD * OdlNewKwd(char *keyword_name, char *value_text, char *pre_comment, char *line_comment, char *file_name, long line_number)
Definition: lablib3.c:1940
unsigned short ExpandIsRecursive(KEYWORD *keyword, char *exp_fname)
Definition: lablib3.c:441
OBJDESC * OdlFindObjDesc(OBJDESC *start_object, const char *object_class, const char *keyword_name, char *keyword_value, unsigned long object_position, unsigned short search_scope)
Definition: lablib3.c:536
int status
Definition: l1_czcs_hdf.c:32
#define L(lambda, T)
Definition: PreprocessP.h:185
short OdlPrintMessage(const char *message_fname, FILE *message_fptr, long line_number, const char *text)
Definition: lablib3.c:3074
#define ODL_TEXT
Definition: lablib3.h:56
char * OdlGetFileSpec(char *fname)
Definition: lablib3.c:2913
short CheckBalance(char *text)
Definition: lablib3.c:5834
#define UpperCase(zstrz)
Definition: oli_toolbox.h:116
data_t root[NROOTS]
Definition: decode_rs.h:78
KEYWORD * OdlFindKwd(OBJDESC *start_object, const char *keyword_name, char *keyword_value, unsigned long keyword_position, unsigned short search_scope)
Definition: lablib3.c:1452
short OdlPrintLine(const char *message_fname, FILE *message_fptr, const char *text)
Definition: lablib3.c:3163
OBJDESC * OdlNewObjDesc(const char *object_class, const char *pre_comment, const char *line_comment, const char *post_comment, const char *end_comment, const char *file_name, short is_a_group, long line_number)
Definition: lablib3.c:1019
#define ReplaceChar(zstrz, zoldz, znewz)
Definition: oli_toolbox.h:109
#define FALSE
Definition: rice.h:164
#define ODL_GROUP
Definition: lablib3.h:66
#define NULL
Definition: decode_rs.h:63
#define ODL_EXPAND_STRUCTURE
Definition: lablib3.h:34
char * OdlValueEnd(char *text)
Definition: lablib3.c:5221
unsigned short OdlDataType(char *text)
Definition: lablib3.c:5373
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)
Definition: lablib3.c:3713
float32 base
Definition: maplists.h:106
char * OdlGetLabelVersion(OBJDESC *object)
Definition: lablib3.c:1102
short odl_suppress_messages
Definition: lablib3.c:34
#define LastChar(zstrz)
Definition: oli_toolbox.h:59
#define ODL_RECORD_LOCATION
Definition: lablib3.h:47
#define ODL_UNKNOWN
Definition: lablib3.h:52
OBJDESC * OdlTraverseTree(OBJDESC *curr_object, unsigned long root_level)
Definition: lablib3.c:4998
#define TRUE
Definition: rice.h:165
KEYWORD * OdlPasteKwdBefore(KEYWORD *new_keyword, KEYWORD *old_keyword)
Definition: lablib3.c:1760
void OdlPrintKeywords(OBJDESC *object, char *message_fname, FILE *message_fptr)
Definition: lablib3.c:3595
#define ODL_SIBLINGS_ONLY
Definition: lablib3.h:42
char * OdlValueRowEnd(char *text)
Definition: lablib3.c:5320
KEYWORD * OdlPasteKwd(KEYWORD *keyword, OBJDESC *object)
Definition: lablib3.c:1699
def remove(file_to_delete)
Definition: ProcUtils.py:319
#define CopyString(zstrz, zoldz)
Definition: oli_toolbox.h:71
KEYWORD * OdlFreeKwd(KEYWORD *keyword)
Definition: lablib3.c:2578
KEYWORD * OdlCopyKwd(KEYWORD *keyword)
Definition: lablib3.c:1880
short OdlValidEndObjDesc(OBJDESC *curr_object, char *equals, char *right_part, char *message_fname, FILE *message_fptr, long line_number, unsigned short group_type)
Definition: lablib3.c:4447
char * OdlFormatMessage(char *text)
Definition: lablib3.c:3207
KEYWORD * OdlGetNextKwd(KEYWORD *keyword)
Definition: lablib3.c:2078
unsigned short OdlWildCardCompare(const char *wildcard_text, const char *plain_text)
Definition: lablib3.c:4844
char * OdlGetKwdUnit(KEYWORD *keyword)
Definition: lablib3.c:2331
#define ODL_CHILDREN_ONLY
Definition: lablib3.h:41
short OdlValidIdentifier(const char *id_name, const char *id_type, const char *message_fname, FILE *message_fptr, long line_number)
Definition: lablib3.c:4524
char ODLErrorMessage[120]
Definition: lablib3.c:3061
OBJDESC * OdlGetObjDescParent(OBJDESC *object)
Definition: lablib3.c:1386
int OdlGetObjDescLevel(OBJDESC *object)
Definition: lablib3.c:1271
#define isdigit(c)
short OdlNestingLevel(char *text, long *brace_nesting, long *paren_nesting)
Definition: lablib3.c:4101
KEYWORD * OdlGetFirstKwd(OBJDESC *object)
Definition: lablib3.c:2024
short OdlValidElement(char *text, char *message_fname, FILE *message_fptr, long line_number, long element_number)
Definition: lablib3.c:4241
short OdlValidObjDesc(OBJDESC *curr_object, char *equals, char *right_part, char *message_fname, FILE *message_fptr, long line_number)
Definition: lablib3.c:4723
#define ODL_EXPAND_CATALOG
Definition: lablib3.h:35
#define AddStringToList(zstrz, zlistz)
Definition: oli_toolbox.h:180
unsigned short MASK
Definition: oli_toolbox.h:148
#define TB_MAXPATH
Definition: oli_toolbox.h:42
#define TB_MAX_BUFFER
Definition: oli_toolbox.h:39
OBJDESC * OdlPasteObjDesc(OBJDESC *new_object, OBJDESC *parent_object)
Definition: lablib3.c:766
#define StripTrailing(zstrz, zstripz)
Definition: oli_toolbox.h:99
char * strdup(const char *)
#define ODL_L7_DATE_TIME_FRAC
Definition: lablib3.h:62
#define TB_MAXFNAME
Definition: oli_toolbox.h:41
char * OdlGetKwdValue(KEYWORD *keyword)
Definition: lablib3.c:2131
OBJDESC * OdlParseLabelFile(char *filespec, char *message_fname, MASK expand, unsigned short suppress_messages)
Definition: lablib3.c:124
OBJDESC * OdlPasteObjDescAfter(OBJDESC *new_object, OBJDESC *old_object)
Definition: lablib3.c:893
#define ODL_OBJECT
Definition: lablib3.h:65
instead the metadata field ProcessingEnvinronment is filled in from the output of a call to the POSIX compliant function uname from within the L1B code A small bug in L1B_Tables an incorrect comparison of RVS coefficients for TEBs to RVS coefficients for RSBs was being made This was replaced with a comparison between TEB coefficients This error never resulted in an incorrect RVS correction but did lead to recalculating the coefficients for each detector in a thermal band even if the coefficients were the same for all detectors To reduce to overall size of the reflective LUT HDF fill values were eliminated from all LUTs previously dimensioned where and where NUM_TIMES is the number of time dependent table pieces In Preprocess a small error where the trailing dropped scan counter was incremented when the leading dropped scan counter should have been was fixed This counter is internal only and is not yet used for any chiefly to casting of were added to make it LINUX compatible Output of code run on LINUX machines displays differences of at most scaled sector incalculable values of the Emissive calibration factor and incalculable values of SV or BB averages was moved outside the loop over frames in Emissive_Cal c since none of these quantities are frame dependent Initialization of b1 and XMS values in Preprocess c routine Process_OBCENG_Emiss was moved inside the detector loops The code was altered so that if up to five scans are dropped between the leading middle or middle trailing the leading or trailing granule will still be used in emissive calibration to form a cross granule average QA bits and are set for a gap between the leading middle and middle trailing granules respectively This may in rare instances lead to a change in emissive calibration coefficients for scans at the beginning or end of a granule A small bug in the Band correction algorithm was corrected an uncertainty value was being checked against an upper bound whereas the proper quantity to be checked was the corresponding which is the product of the Band radiance times the ratio of the Band to Band scaling factors times the LUT correction value for that detector In addition a new LUT which allows for a frame offset with regard to the Band radiance was added A LUT which switches the correction off or on was also added Changes which do not affect scientific output of the the pixel is flagged with the newly created flag and the number of pixels for which this occurs is counted in the QA_common table The array of b1s in Preprocess c was being initialized to outside the loop over which meant that if b1 could not be the value of b1 from the previous band for that scan detector combination was used The initialization was moved inside the band loop Minor code changes were made to eliminate compiler warnings when the code is compiled in bit mode Temperature equations were upgraded to be MODIS AQUA or MODIS TERRA specific and temperature conversion coefficients for AQUA were MOD_PR02 will not cease execution if the value of this parameter is not but will print a message
Definition: HISTORY.txt:644
KEYWORD * OdlNextKwd(KEYWORD *start_keyword, char *keyword_name, char *keyword_value, unsigned long keyword_position, unsigned short search_scope)
Definition: lablib3.c:1538
KEYWORD * OdlPasteKwdAfter(KEYWORD *new_keyword, KEYWORD *old_keyword)
Definition: lablib3.c:1820
int OdlGetObjDescChildCount(OBJDESC *object)
Definition: lablib3.c:1217
short OdlValidValueList(char *text, char *message_fname, FILE *message_fptr, long line_number)
Definition: lablib3.c:4763
#define TB_MAXLINE
Definition: oli_toolbox.h:40
short OdlValidKwd(OBJDESC *curr_object, char *left_part, char *equals, char *right_part, char *message_fname, FILE *message_fptr, long line_number)
Definition: lablib3.c:4609
#define CloseMe(zfptrz)
Definition: oli_toolbox.h:56
OBJDESC * OdlParseLabelString(char *odl_string, char *message_fname, MASK expand, unsigned short suppress_messages)
Definition: lablib3.c:196
OBJDESC * OdlCopyObjDesc(OBJDESC *object)
Definition: lablib3.c:956
char * OdlGetObjDescClassName(OBJDESC *object)
Definition: lablib3.c:1167
#define ODL_SET
Definition: lablib3.h:60
#define NewString(zstrz, zsizez)
Definition: oli_toolbox.h:61
TB_STRING_LIST * OdlGetAllKwdValues(KEYWORD *keyword)
Definition: lablib3.c:2200
char * OdlGetKwdName(KEYWORD *keyword)
Definition: lablib3.c:2401
char * OdlTypeString(unsigned short type, char *type_string)
Definition: lablib3.c:5715
short OdlValidBraces(char *text, long brace_nesting, long paren_nesting, char *message_fname, FILE *message_fptr, long line_number)
Definition: lablib3.c:4146
KEYWORD * OdlFreeAllKwds(OBJDESC *object)
Definition: lablib3.c:2520
FILE * OdlOpenMessageFile(const char *message_fname, FILE *message_fptr)
Definition: lablib3.c:2648
unsigned short OdlGetKwdValueType(KEYWORD *keyword)
Definition: lablib3.c:2280
#define ODL_SYMBOL
Definition: lablib3.h:55
level
Definition: mapgen.py:186
#define ODL_THIS_OBJECT
Definition: lablib3.h:43
#define StripLeading(zstrz, zstripz)
Definition: oli_toolbox.h:93
char * OdlValueRowStart(char *text)
Definition: lablib3.c:5274
#define ODL_BYTE_LOCATION
Definition: lablib3.h:48
#define ODL_DATE
Definition: lablib3.h:57
char * OdlGetFileName(KEYWORD *keyword, unsigned long *start_location, unsigned short *start_location_type)
Definition: lablib3.c:2784
data_t u
Definition: decode_rs.h:74
this program makes no use of any feature of the SDP Toolkit that could generate such a then geolocation is calculated at that and then aggregated up to Resolved feature request Bug by adding three new int8 SDSs for each high resolution offsets between the high resolution geolocation and a bi linear interpolation extrapolation of the positions This can be used to reconstruct the high resolution geolocation Resolved Bug by delaying cumulation of gflags until after validation of derived products Resolved Bug by setting Latitude and Longitude to the correct fill resolving to support Near Real Time because they may be unnecessary if use of entrained ephemeris and attitude data is turned resolving bug report Corrected to filter out Aqua attitude records with missing status helping resolve bug MOD_PR03 will still correctly write scan and pixel data that does not depend upon the start time
Definition: HISTORY.txt:248
void OdlPrintHierarchy(OBJDESC *object, char *message_fname, FILE *message_fptr)
Definition: lablib3.c:3363
#define isalpha(c)
#define ODL_DATE_TIME
Definition: lablib3.h:58
OBJDESC * OdlFreeTree(OBJDESC *object)
Definition: lablib3.c:2459
OBJDESC * OdlPasteObjDescBefore(OBJDESC *new_object, OBJDESC *old_object)
Definition: lablib3.c:830
void OdlAdjustObjDescLevel(OBJDESC *object)
Definition: lablib3.c:1329
#define ODL_INTEGER
Definition: lablib3.h:53
long odl_message_count
Definition: lablib3.c:33
#define ODL_NOEXPAND
Definition: lablib3.h:33
#define ODL_SEQUENCE
Definition: lablib3.h:59
char * OdlTempFname()
Definition: lablib3.c:5787
KEYWORD * OdlCutKwd(KEYWORD *keyword)
Definition: lablib3.c:1634
#define AppendString(zstrz, znewz)
Definition: oli_toolbox.h:80
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed as required for compatibility with version of the SDP toolkit Corrected test output file names to end in per delivery and then split off a new MYD_PR03 pcf file for Aqua Added AssociatedPlatformInstrumentSensor to the inventory metadata in MOD01 mcf and MOD03 mcf Created new versions named MYD01 mcf and MYD03 where AssociatedPlatformShortName is rather than Terra The program itself has been changed to read the Satellite Instrument validate it against the input L1A and LUT and to use it determine the correct files to retrieve the ephemeris and attitude data from Changed to produce a LocalGranuleID starting with MYD03 if run on Aqua data Added the Scan Type file attribute to the Geolocation copied from the L1A and attitude_angels to radians rather than degrees The accumulation of Cumulated gflags was moved from GEO_validate_earth_location c to GEO_locate_one_scan c
Definition: HISTORY.txt:464
#define SayGoodbye()
Definition: oli_toolbox.h:58
#define StripUnprintables(zstrz)
Definition: oli_toolbox.h:104
char * OdlFirstWord(char *text)
Definition: lablib3.c:5076
OBJDESC * OdlExpandLabelFile(OBJDESC *object, char *message_fname, MASK expand, unsigned short suppress_messages)
Definition: lablib3.c:280
int i
Definition: decode_rs.h:71
char * OdlValueStart(char *text)
Definition: lablib3.c:5174
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
char * OdlNextWord(char *text)
Definition: lablib3.c:5126
#define ODL_REAL
Definition: lablib3.h:54
version
Definition: setup.py:15
#define ODL_RECURSIVE_DOWN
Definition: lablib3.h:39
OBJDESC * OdlCutObjDesc(OBJDESC *object)
Definition: lablib3.c:702