Main Page | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

md.c

Go to the documentation of this file.
00001 /*****************************************************************************\
00002  *  Copyright  1995  The Board of Trustees of the University of Illinois.
00003  *  All rights reserved.
00004  *
00005  *  md.c, part of the interface to the internal representation of the 
00006  *  IMPACT Meta-Description Language
00007  *  John C. Gyllenhaal, Wen-mei Hwu, and The IMPACT Research Group
00008  *  Coordinated Science Laboratory
00009  *  University of Illinois at Urbana-Champaign
00010  *
00011  *  The IMPACT Research Group may be contacted at impact@crhc.uiuc.edu.
00012  *
00013  *  md.c (part of the interface to the internal representation of the
00014  *  IMPACT Meta-Description Language software), including both binary 
00015  *  and source (hereafter, Software) is copyrighted by The Board of Trustees
00016  *  of the University of Illinois (UI), and ownership remains with the UI.
00017  *
00018  *  The UI grants you (hereafter, Licensee) a license to use the Software for
00019  *  academic, research and internal business purposes only, without a fee.
00020  *  Licensee may distribute the Software to third parties provided that the
00021  *  copyright notice and this statement appears on all copies and that no
00022  *  charge is associated with such copies.
00023  *
00024  *  Licensee may make derivative works.  However, if Licensee distributes
00025  *  any derivative work based on or derived from the Software, then Licensee
00026  *  will clearly notify users that such derivative work is a modified
00027  *  version and not the original Software distributed by the UI.
00028  *
00029  *  Any Licensee wishing to make commercial use of the Software should contact
00030  *  the UI, c/o the Research and Technology Management Office [rtmo@uiuc.edu],
00031  *  to negotiate an appropriate license for such commercial use.  Commercial
00032  *  use includes (1) integration of all or part of the source code into a
00033  *  product for sale or license by or on behalf of Licensee to third parties,
00034  *  or (2) distribution of the Software to third parties that need it to
00035  *  utilize a commercial product sold or licensed by or on behalf of Licensee.
00036  *
00037  *  UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
00038  *  ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
00039  *  THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE USERS OF THIS
00040  *  SOFTWARE.
00041  *
00042  *  By using or copying this Software, Licensee agrees to abide by the
00043  *  copyright law and all other applicable laws of the U.S. including, but
00044  *  not limited to, export control laws, and the terms of this license.
00045  *  UI shall have the right to terminate this license immediately by written
00046  *  notice upon Licensee's breach of, or non-compliance with, any of its terms.
00047  *  Licensee may be held legally responsible for any copyright infringement
00048  *  that is caused or encouraged by Licensee's failure to abide by the terms
00049  *  of this license.
00050  *
00051  *  Form approved by University Counsel, M.A.R., 05/10/93
00052 \*****************************************************************************/
00053 /*****************************************************************************\
00054  *      File:   md.c
00055  *
00056  *      Description: The interface to the internal representation of the
00057  *                   IMPACT Meta-Description Language
00058  *
00059  *      Creation Date:  March 1995
00060  *
00061  *      Authors: John C. Gyllenhaal and Wen-mei Hwu
00062  *
00063  *      Revisions:
00064  *           Shail Aditya (HP Labs)  February 1996
00065  *           Changed MD_get_xxx() arguments to be consistent with MD_set_xxx()
00066  *           Added MD_num_xxx() which returns number of sections, entries, etc.
00067  *
00068  *           John C. Gyllenhaal  May 1996
00069  *           Folded Shail's changes back into IMPACT's version
00070  *           Changed low-level representation to use hex for integers
00071  *           Added MD_rename_entry(), MD_delete_element(), MD_max_field_index()
00072  *                 MD_max_element_index, and MD_print_md_declarations()
00073  *           Changed all error messages to uniformly use MD_punt()
00074  *
00075  *           John C. Gyllenhaal July 1996
00076  *           Implemented Shail Aditya's suggestion of adding void pointers to
00077  *           MD_Section and MD_Entry for the user's use.  Added functions
00078  *           MD_set_section_ext(), MD_get_section_ext(), MD_set_entry_ext(), 
00079  *           and MD_get_entry_ext().
00080  *
00081 \*****************************************************************************/
00082 
00083 #ifndef lint
00084 #define lint
00085 static char copyright[] =
00086 "@(#) Copyright (c) 1995 The Board of Trustees of the University of Illinois.\
00087 \nAll rights reserved.\n";
00088 #endif
00089 
00090 /* Turn on debugging macros */
00091 #define MD_DEBUG_MACROS 
00092 
00093 #include <stdio.h>
00094 #include <stdlib.h>
00095 #include <string.h>
00096 #include "md.h"
00097 #include <stdarg.h>
00098 #include <ctype.h>
00099 #include "l_alloc_new.h"
00100 
00101 
00102 /* Internal buffer structure used by MD_read_md(),
00103  *  MD_read_double(), MD_read_string().
00104  */
00105 typedef struct MD_Buf
00106 {
00107     char        *buf;
00108     int         buf_size;
00109 } MD_Buf;
00110 
00111 /* Internal pool used by read routines only */
00112 static L_Alloc_Pool *MD_Buf_pool = NULL;
00113 
00114 /* L_Alloc pool declarations */
00115 static L_Alloc_Pool *MD_pool = NULL;
00116 static L_Alloc_Pool *MD_Symbol_Table_pool = NULL;
00117 static L_Alloc_Pool *MD_Symbol_pool = NULL;
00118 static L_Alloc_Pool *MD_Section_pool = NULL;
00119 static L_Alloc_Pool *MD_Entry_pool = NULL;
00120 static L_Alloc_Pool *MD_Field_Decl_pool = NULL;
00121 static L_Alloc_Pool *MD_Element_Req_pool = NULL;
00122 static L_Alloc_Pool *MD_Field_pool = NULL;
00123 static L_Alloc_Pool *MD_Element_pool = NULL;
00124 
00125 /* Create a type array for error checking */
00126 static char *MD_type_name[] = {"(UNDEFINED)", "INT", "DOUBLE", "STRING", 
00127                                "LINK", "(UNDEFINED)"};
00128 
00129 /* Prototypes of interal static routines */
00130 static void MD_resize_field_arrays (MD_Section *section, int max_index);
00131 static void MD_resize_element_array (MD_Field *field, int max_index);
00132 static int MD_legal_ident (char *ident);
00133 
00134 
00135 /*
00136  * Internal md library routines.  
00137  * Should not be used by non-library routines.
00138  */
00139 
00140 /* Error routine, fmt and trailing args are the same as printf.  
00141  * Adds header message identifying error as coming from MD_library and
00142  * which md caused the error.
00143  * Exits with value 1.
00144  */
00145 static void MD_punt (MD *md, char *fmt, ...)
00146 {
00147     va_list args;
00148 
00149     /* Print error message header.
00150      * Allow NULL to be passed in for md 
00151      */
00152     fprintf (stderr, "\nMD library error");
00153     if (md == NULL)
00154         fprintf (stderr, ":\n");
00155     else
00156         fprintf (stderr, " (in \"%s\"):\n", md->name);
00157 
00158     /* Print out error message */
00159     va_start (args, fmt);
00160     vfprintf (stderr, fmt, args);
00161     va_end(args);
00162     fprintf (stderr,"\n");
00163 
00164     exit (1);
00165 }
00166 
00167 /* MD warning routine, args are the same as fprintf.  
00168  * Prints message to outand returns to caller.
00169  *
00170  * Provided as a useful place to place a breakpoint when debugging warnings.
00171  */
00172 static void MD_warn (FILE *out, char *fmt, ...)
00173 {
00174     va_list args;
00175 
00176     /* Make sure warning goes on new line */
00177     fprintf (out, "\n");
00178 
00179     /* Print out warning message */
00180     va_start (args, fmt);
00181     vfprintf (out, fmt, args);
00182     va_end(args);
00183 
00184     /* Automatically add newline to warning */
00185     fprintf (out,"\n");
00186 }
00187 
00188 /* MD Symbol table code for md section, entry and field names.
00189  * Internal MD use only!  Not designed to be used by non-MD functions!
00190  */
00191 /* Malloc's a string buffer and concatinates the two strings into it.
00192  * This newly malloced bufffer is returned.
00193  * 
00194  * Used by MD to build descriptive names for symbol tables.
00195  */
00196 static char *MD_concat_strings (char *string1, char *string2)
00197 {
00198     char *buf;
00199     int len;
00200 
00201     /* The buffer length needed is the length of both strings plus 1 for
00202      * the terminator.
00203      */
00204     len = strlen (string1) + strlen (string2) + 1;
00205     if ((buf = (char *) malloc (len * sizeof(char))) == NULL)
00206     {
00207         MD_punt (NULL,
00208                  "MD_concat_strings: Out of memory mallocing buffer (size %i)",
00209                  len);
00210     }
00211 
00212     /* Concat strings */
00213     sprintf (buf, "%s%s", string1, string2);
00214 
00215     /* Return concatinated strings */
00216     return (buf);
00217 }
00218 
00219 /* Create and initialize MD_Symbol_Table.
00220  * Creates a hash table of initial size 2 * expected_size rounded up
00221  * to the closest power of two.  (Min hash size 32)
00222  */
00223 static MD_Symbol_Table *MD_new_symbol_table (MD *md, char *name, 
00224                                              int expected_size)
00225 {
00226     MD_Symbol_Table *table;
00227     MD_Symbol **hash;
00228     unsigned int min_size, hash_size;
00229     unsigned int i;
00230 
00231 
00232     /* If expected size negative, force to be 0 */
00233     if (expected_size < 0)
00234         expected_size = 0;
00235 
00236     /* To prevent infinite loop by sizing algorithm (and running out of
00237      * memory :) ), expected_size must be <= a billion.
00238      */
00239     if (expected_size > 1000000000)
00240         MD_punt (md, "MD_Symbol_Table: unreasonable expected_size (%u)",
00241                  expected_size);
00242 
00243     /* Want a minumum size of at least twice the expected size */
00244     min_size = expected_size * 2;
00245 
00246     /* Start with a minumum hash size of 32.  
00247      * (Smaller sizes don't work as well with the hashing algorithm)
00248      */
00249     hash_size = 32;
00250 
00251     /* Double hash_size until min_size is reached or exceeded */
00252     while (hash_size < min_size)
00253         hash_size = hash_size << 1;
00254 
00255     
00256     /* Sanity check (debugging purposes) */
00257     if (MD_Symbol_Table_pool == NULL)
00258     {
00259         MD_punt (NULL, 
00260                  "MD routines not initialized (call MD_new_md() first)!");
00261         
00262     }
00263 
00264     /* Allocate symbol table */
00265     table = (MD_Symbol_Table *) L_alloc (MD_Symbol_Table_pool);
00266 
00267     /* Allocate array for hash */
00268     hash = (MD_Symbol **) malloc (hash_size * sizeof(MD_Symbol *));
00269     if (hash == NULL)
00270     {
00271         MD_punt (md, "MD_new_symbol_table: Out of memory, hash array size %i.",
00272                  hash_size);
00273     }
00274 
00275     /* Initialize hash table */
00276     for (i=0; i < (int) hash_size; i++)
00277         hash[i] = NULL;
00278 
00279     /* Initialize fields */
00280     table->md = md;
00281     table->name = strdup (name);
00282     table->hash = hash;
00283     table->hash_size = hash_size;
00284     table->hash_mask = hash_size -1; /* AND mask, works only for power of 2 */
00285     /* Resize when count at 75% of hash_size */
00286     table->resize_size = hash_size - (hash_size >> 2);
00287     table->head_symbol = NULL;
00288     table->tail_symbol = NULL;
00289     table->symbol_count = 0;
00290 
00291     return (table);
00292 }
00293 
00294 /* Frees the symbol table, and optionally frees the data pointed to */
00295 void MD_delete_symbol_table (MD_Symbol_Table *table, 
00296                              void (*free_routine)(void *))
00297 {
00298     MD_Symbol *symbol, *next_symbol;
00299 
00300     /* For all the symbols in the table, free each one */
00301     for (symbol = table->head_symbol; symbol != NULL;
00302          symbol = next_symbol)
00303     {
00304         /* Get the next symbol before deleting this one */
00305         next_symbol = symbol->next_symbol;
00306 
00307         /* If free routine specified, free data */
00308         if (free_routine != NULL)
00309             free_routine (symbol->data);
00310 
00311         /* Free symbol structure */
00312         L_free (MD_Symbol_pool, symbol);
00313     }
00314 
00315     /* Free the hash array and table name*/
00316     free (table->hash);
00317     free (table->name);
00318 
00319     /* Free the table structure */
00320     L_free (MD_Symbol_Table_pool, table);
00321 }
00322 
00323 /* Doubles the symbol table hash array size */
00324 static void MD_resize_symbol_table (MD_Symbol_Table *table)
00325 {
00326     MD_Symbol **new_hash, *symbol, *hash_head;
00327     int new_hash_size;
00328     unsigned int new_hash_mask, new_hash_index;
00329     int i;
00330 
00331     /* Double the size of the hash array */
00332     new_hash_size = table->hash_size * 2;
00333 
00334     /* Allocate new hash array */
00335     new_hash = (MD_Symbol **) malloc (new_hash_size * sizeof (MD_Symbol *));
00336     if (new_hash == NULL)
00337     {
00338         MD_punt (table->md, 
00339                  "MD_resize_symbol_table: Out of memory, new size %i.",
00340                  new_hash_size);
00341     }
00342 
00343     /* Initialize new hash table */
00344     for (i=0; i < new_hash_size; i++)
00345         new_hash[i] = NULL;
00346 
00347     /* Get the hash mask for the new hash table */
00348     new_hash_mask = new_hash_size -1; /* AND mask, works only for power of 2 */
00349     
00350     /* Go though all the symbol and add to new hash table.
00351      * Can totally disreguard old hash links.
00352      */
00353     for (symbol = table->head_symbol; symbol != NULL; 
00354          symbol = symbol->next_symbol)
00355     {
00356         /* Get index into hash table to use for this name */
00357         new_hash_index = symbol->hash_val & new_hash_mask;
00358         
00359         /* Add symbol to head of linked list */
00360         hash_head = new_hash[new_hash_index];
00361         symbol->next_hash = hash_head;
00362         symbol->prev_hash = NULL;
00363         if (hash_head != NULL)
00364             hash_head->prev_hash = symbol;
00365         new_hash[new_hash_index] = symbol;
00366     }
00367 
00368     /* Free old hash table */
00369     free (table->hash);
00370    
00371     /* Initialize table fields for new hash table */
00372     table->hash = new_hash;
00373     table->hash_size = new_hash_size;
00374     table->hash_mask = new_hash_mask;
00375     /* Resize when count at 75% of new_hash_size */
00376     table->resize_size = new_hash_size - (new_hash_size >> 2); 
00377 }
00378 
00379 /* Hashes a string, returning an unsigned 32 bit number. */
00380 static unsigned int MD_hash_string (char *string)
00381 {
00382     unsigned int hash_val;
00383     unsigned char *ptr;
00384     unsigned int ch;
00385     
00386     hash_val = 0;
00387 
00388     /* Scan through all the characters, adding the characters to the
00389      * hash value.  Multiply the hash value by 17 (using shifts) before
00390      * adding each character in.
00391      * 
00392      * This very quick hash algorithm was tuned to work well with
00393      * strings ending with numbers.
00394      */
00395     ptr = (unsigned char *) string;
00396     while ((ch = *ptr) != 0)
00397     {
00398         /* Multiply hash_val by 17 by adding 16*hash_val to it.
00399          * (Use a shift, integer multiply is usually very expensive)
00400          */
00401         hash_val += (hash_val << 4);
00402 
00403         /* Add in character value */
00404         hash_val += ch;
00405 
00406         /* Goto next character */
00407         ptr ++;
00408     }
00409 
00410     /* Return the hash value */
00411     return (hash_val);
00412 }
00413 
00414 /* Adds MD structure to symbol table, name and data are not copied!!! 
00415  * Dynamically increases symbol table's hash array.
00416  * Returns pointer to added symbol.
00417  */
00418 static MD_Symbol *MD_add_symbol (MD_Symbol_Table *table, char *name, 
00419                                  void *data)
00420 {
00421     MD_Symbol *symbol, *hash_head, *check_symbol, *tail_symbol;
00422     unsigned int hash_val, hash_index;
00423     int symbol_count;
00424 
00425     /* Increase symbol table size if necessary before adding new symbol.  
00426      * This will change the hash_mask if the table is resized!
00427      */
00428     symbol_count = table->symbol_count;
00429     if (symbol_count >= table->resize_size)
00430     {
00431         MD_resize_symbol_table (table);
00432     }
00433 
00434     /* Allocate a symbol (pool initialized in create table routine)*/
00435     symbol = (MD_Symbol *) L_alloc (MD_Symbol_pool);
00436     
00437     /* Initialize fields */
00438     symbol->name = name;
00439     symbol->data = data;
00440     symbol->table = table;
00441     symbol->symbol_id = -1;     /* Used by MD_write_md only */
00442 
00443     /* Get tail symbol for ease of use */
00444     tail_symbol = table->tail_symbol;
00445 
00446     /* Add to linked list of symbols */
00447     symbol->next_symbol = NULL;
00448     symbol->prev_symbol = tail_symbol;
00449 
00450     if (tail_symbol == NULL)
00451         table->head_symbol = symbol;
00452     else
00453         tail_symbol->next_symbol = symbol;
00454     table->tail_symbol = symbol;
00455 
00456     /* Get hash value of name and put in symbol structure for quick compare
00457      * and table resize.
00458      */
00459     hash_val = MD_hash_string (name);
00460     symbol->hash_val = hash_val;
00461 
00462     /* Get index into hash table to use for this name */
00463     hash_index = hash_val & table->hash_mask;
00464     
00465     /* Get head symbol in current linked list for ease of use */
00466     hash_head = table->hash[hash_index];
00467 
00468     
00469     /* Sanity check (may want to ifdef out later).
00470      *
00471      * Check that this symbol's name is not already in the symbol table.
00472      * Punt if it is, since can cause a major debugging nightmare.
00473      */
00474     for (check_symbol = hash_head; check_symbol != NULL;
00475          check_symbol = check_symbol->next_hash)
00476     {
00477         /* Check hash value before doing strcmp to avoid function
00478          * call when possible.
00479          */
00480         if ((check_symbol->hash_val == hash_val) &&
00481             (strcmp(check_symbol->name, name) == 0))
00482         {
00483             MD_punt (table->md, 
00484                      "%s: cannot add '%s', already in table!",
00485                      table->name, name);
00486         }
00487     }
00488     
00489 
00490     /* Add symbol to head of linked list */
00491     symbol->next_hash = hash_head;
00492     symbol->prev_hash = NULL;
00493     if (hash_head != NULL)
00494         hash_head->prev_hash = symbol;
00495     table->hash[hash_index] = symbol;
00496 
00497     /* Update table's symbol count */
00498     table->symbol_count = symbol_count + 1;
00499 
00500     /* Return symbol added */
00501     return (symbol);
00502 }
00503 
00504 /* Renames a symbol (name is still not copied and old name is not freed!)
00505  * Punts if new name is already in symbol table.
00506  */
00507 static void MD_rename_symbol (MD_Symbol *symbol, char *new_name)
00508 {
00509     MD_Symbol_Table *table;
00510     MD_Symbol *hash_head, *check_symbol;
00511     unsigned int hash_val, hash_index;
00512 
00513     /* Get symbol table for ease of use */
00514     table = symbol->table;
00515 
00516 
00517     /* Get index into hash table for old name */
00518     hash_index = symbol->hash_val & table->hash_mask;
00519 
00520     /* Remove symbol hash linked list */
00521     if (symbol->prev_hash == NULL)
00522         table->hash[hash_index] = symbol->next_hash;
00523     else
00524         symbol->prev_hash->next_hash = symbol->next_hash;
00525 
00526     if (symbol->next_hash != NULL)
00527         symbol->next_hash->prev_hash = symbol->prev_hash;
00528     
00529 
00530     /* Get hash value of new name and put in symbol structure for quick compare
00531      * and table resize.
00532      */
00533     symbol->name = new_name;
00534     hash_val = MD_hash_string (new_name);
00535     symbol->hash_val = hash_val;
00536 
00537     /* Get index into hash table to use for this name */
00538     hash_index = hash_val & table->hash_mask;
00539     
00540     /* Get head symbol in current linked list for ease of use */
00541     hash_head = table->hash[hash_index];
00542 
00543     /* 
00544      * Check that this symbol's name is not already in the symbol table.
00545      * Punt if it is, since can cause a major debugging nightmare.
00546      */
00547     for (check_symbol = hash_head; check_symbol != NULL;
00548          check_symbol = check_symbol->next_hash)
00549     {
00550         /* Check hash value before doing strcmp to avoid function
00551          * call when possible.
00552          */
00553         if ((check_symbol->hash_val == hash_val) &&
00554             (strcmp(check_symbol->name, new_name) == 0))
00555         {
00556             MD_punt (table->md, 
00557                      "%s: cannot rename to '%s', already in table!",
00558                      table->name, new_name);
00559         }
00560     }
00561     
00562 
00563     /* Add symbol to head of linked list */
00564     symbol->next_hash = hash_head;
00565     symbol->prev_hash = NULL;
00566     if (hash_head != NULL)
00567         hash_head->prev_hash = symbol;
00568     table->hash[hash_index] = symbol;
00569 }
00570 
00571 /* Returns a MD_Symbol structure with the desired name, or NULL
00572  * if the name is not in the symbol table.
00573  */
00574 static MD_Symbol *MD_find_symbol (MD_Symbol_Table *table, char *name)
00575 {
00576     MD_Symbol *symbol;
00577     unsigned int hash_val, hash_index;
00578 
00579     /* Get the hash value for the name */
00580     hash_val = MD_hash_string (name);
00581 
00582     /* Get the index into the hash table */
00583     hash_index = hash_val & table->hash_mask;
00584 
00585     /* Search the linked list for matching name */
00586     for (symbol = table->hash[hash_index]; symbol != NULL; 
00587          symbol = symbol->next_hash)
00588     {
00589         /* Compare hash_vals first before using string compare */
00590         if ((symbol->hash_val == hash_val) &&
00591             (strcmp(symbol->name, name) == 0))
00592         {
00593             return (symbol);
00594         }
00595     }
00596     return (NULL);
00597 }
00598 
00599 /* 
00600  * DO NOT CALL DIRECTLY!  FOR USE ONLY BY MD MACROS AND ROUTINES!
00601  * Returns the data for desired name, or NULL
00602  * if the name is not in the symbol table.
00603  */
00604 void *_MD_find_symbol_data (MD_Symbol_Table *table, char *name)
00605 {
00606     MD_Symbol *symbol;
00607     unsigned int hash_val, hash_index;
00608 
00609     /* Get the hash value for the name */
00610     hash_val = MD_hash_string (name);
00611 
00612     /* Get the index into the hash table */
00613     hash_index = hash_val & table->hash_mask;
00614 
00615     /* Search the linked list for matching name */
00616     for (symbol = table->hash[hash_index]; symbol != NULL; 
00617          symbol = symbol->next_hash)
00618     {
00619         /* Compare hash_vals first before using string compare */
00620         if ((symbol->hash_val == hash_val) &&
00621             (strcmp(symbol->name, name) == 0))
00622         {
00623             return (symbol->data);
00624         }
00625     }
00626     return (NULL);
00627 }
00628 
00629 /* Deletes symbol and optionally deletes the data using the free routine */
00630 void MD_delete_symbol (MD_Symbol *symbol, void (*free_routine)(void *))
00631 {
00632     MD_Symbol_Table *table;
00633     MD_Symbol *next_hash, *prev_hash, *next_symbol, *prev_symbol;
00634     unsigned int hash_index;
00635 
00636     /* Get the table the symbol is from */
00637     table = symbol->table;
00638 
00639     /* Get the hash index from the symbol's hash_val */
00640     hash_index = symbol->hash_val & table->hash_mask;
00641 
00642     /* Remove symbol from hash table */
00643     prev_hash = symbol->prev_hash;
00644     next_hash = symbol->next_hash;
00645     if (prev_hash == NULL)
00646         table->hash[hash_index] = next_hash;
00647     else
00648         prev_hash->next_hash = next_hash;
00649 
00650     if (next_hash != NULL)
00651         next_hash->prev_hash = prev_hash;
00652 
00653     /* Remove symbol from symbol list */
00654     prev_symbol = symbol->prev_symbol;
00655     next_symbol = symbol->next_symbol;
00656     if (prev_symbol == NULL)
00657         table->head_symbol = next_symbol;
00658     else
00659         prev_symbol->next_symbol = next_symbol;
00660 
00661     if (next_symbol == NULL)
00662         table->tail_symbol = prev_symbol;
00663     else
00664         next_symbol->prev_symbol = prev_symbol;
00665 
00666 
00667     /* If free routine specified, free symbol data */
00668     if (free_routine != NULL)
00669         free_routine (symbol->data);
00670 
00671     /* Free symbol structure */
00672     L_free (MD_Symbol_pool, symbol);
00673 
00674     /* Decrement table symbol count */
00675     table->symbol_count --;
00676 }
00677 
00678 
00679 
00680 /* Prints out the symbol table's hash table (debug routine) */
00681 static void MD_print_symbol_table_hash (FILE *out, MD_Symbol_Table *table)
00682 {
00683     int hash_index, lines;
00684 #if 0
00685     MD_Symbol *symbol;
00686 #endif
00687 
00688     /* Count lines used in table */
00689     lines = 0;
00690     for (hash_index = 0; hash_index < table->hash_size; hash_index++)
00691     {
00692         if (table->hash[hash_index] != NULL)
00693             lines++;
00694     }
00695     fprintf (out, "%s has %i entries (hash size %i, used %i):\n", 
00696              table->name, table->symbol_count, table->hash_size, lines);
00697 
00698 #if 0
00699     /* For each hash_index in hash table */
00700     for (hash_index = 0; hash_index < table->hash_size; hash_index++)
00701     {
00702         /* Skip empty lines */
00703         if (table->hash[hash_index] == NULL)
00704             continue;
00705 
00706         fprintf (out, "%4i:", hash_index);
00707         for (symbol = table->hash[hash_index]; symbol != NULL; 
00708              symbol = symbol->next_hash)
00709         {
00710             fprintf (out, " %s(%i)", symbol->name, symbol->hash_val);
00711         }
00712         fprintf (out, "\n");
00713     }
00714 #endif
00715 }
00716 
00717 /* Creates a new MD with an initial size suitable for the specified
00718  * number of sections.  The MD automatically resizes (upward) when
00719  * appropriate, so 0 sections may be specified.
00720  */
00721 MD *MD_new_md (char *name, int num_sections)
00722 {
00723     MD *md;
00724 
00725     /* If the expected number of sections is negative, force to be 0 */
00726     if (num_sections < 0)
00727         num_sections = 0;
00728 
00729     /* To catch improperly specified num_sections, ensure that the
00730      * expected size is less than a billion.  (Also prevents symbol
00731      * table routines from punting.)
00732      */
00733     if (num_sections > 1000000000)
00734         MD_punt (NULL, "MD_new_md: unreasonable num_sections (%u)",
00735                  num_sections);
00736 
00737     /* Initialize all the pools used by the MD routines on first call
00738      * to MD_new_md().
00739      */
00740     if (MD_pool == NULL)
00741     {
00742         MD_pool = L_create_alloc_pool ("MD", sizeof (MD), 1);
00743         MD_Symbol_Table_pool = L_create_alloc_pool ("MD_Symbol_Table",
00744                                                     sizeof (MD_Symbol_Table), 
00745                                                     16);
00746         MD_Symbol_pool = L_create_alloc_pool ("MD_Symbol", sizeof (MD_Symbol),
00747                                               64);
00748         MD_Section_pool = L_create_alloc_pool ("MD_Section", 
00749                                                sizeof(MD_Section), 16);
00750         MD_Field_Decl_pool = L_create_alloc_pool ("MD_Field_Decl",
00751                                                   sizeof(MD_Field_Decl), 16);
00752         MD_Element_Req_pool = L_create_alloc_pool ("MD_Element_Req",
00753                                                   sizeof(MD_Element_Req), 64);
00754         MD_Entry_pool = L_create_alloc_pool ("MD_Entry", sizeof(MD_Entry), 64);
00755         MD_Field_pool = L_create_alloc_pool ("MD_Field", sizeof(MD_Field), 64);
00756         MD_Element_pool = L_create_alloc_pool ("MD_Element", 
00757                                                sizeof(MD_Element), 64);
00758     }
00759 
00760     /* Allocate new md */
00761     md = (MD *) L_alloc (MD_pool);
00762 
00763     /* Initialize fields */
00764     md->name = strdup (name);
00765     md->section_table = MD_new_symbol_table (md, "Section table", 
00766                                              num_sections);
00767 
00768     /* Return new md */
00769     return (md);
00770 }
00771 
00772 /* Frees up all memory associated with the md.
00773  * If no other mds are allocated, free up the memory used by
00774  * the L_alloc memory manager.
00775  */
00776 void MD_delete_md (MD *md)
00777 {
00778     char *name;
00779 
00780     /* Free name last (for error messages) */
00781     name = md->name;
00782 
00783     /* Free section symbol table and all the information contained in it. */
00784     MD_delete_symbol_table (md->section_table, 
00785                             (void(*)(void *))_MD_free_section);
00786 
00787     /* Free the md structure */
00788     L_free (MD_pool, md);
00789 
00790     /* If no other mds are allocated, attempt to free the memory
00791      * used by the L_alloc memory manager.
00792      */
00793     if (MD_pool->allocated == MD_pool->free)
00794     {
00795         /* The following free routines will give warnings if some
00796          * of the allocated memory is still in use.
00797          * We will through away the memory unfreed if this
00798          * occurs (it shouldn't!)
00799          */
00800         L_free_alloc_pool (MD_pool);
00801         L_free_alloc_pool (MD_Symbol_Table_pool);
00802         L_free_alloc_pool (MD_Symbol_pool);
00803         L_free_alloc_pool (MD_Section_pool);
00804         L_free_alloc_pool (MD_Entry_pool);
00805         L_free_alloc_pool (MD_Field_Decl_pool);
00806         L_free_alloc_pool (MD_Element_Req_pool);
00807         L_free_alloc_pool (MD_Field_pool);
00808         L_free_alloc_pool (MD_Element_pool);
00809 
00810         /* Set all pool pointer's to NULL to prevent use of freed memory
00811          * (and to signal that pools need to be initialized if used)
00812          */
00813         MD_pool = NULL;
00814         MD_Symbol_Table_pool = NULL;
00815         MD_Symbol_pool = NULL;
00816         MD_Section_pool = NULL;
00817         MD_Entry_pool = NULL;
00818         MD_Field_Decl_pool = NULL;
00819         MD_Element_Req_pool = NULL;
00820         MD_Field_pool = NULL;
00821         MD_Element_pool = NULL;
00822     }
00823 
00824     /* Free the md's name */
00825     free (name);
00826 }
00827 
00828 /*
00829  * This function checks the elements in the specified md.
00830  * 
00831  * Returns the number of required fields not specified + the 
00832  * number of elements with incorrect type in the entire md (0 if all ok).
00833  * 
00834  * If out is non-NULL, warning messages for non-specified required field
00835  * and for each element with incorrect type will be printed to out.
00836  */
00837 int MD_check_md (FILE *out, MD *md)
00838 {
00839     MD_Symbol *symbol;
00840     MD_Section *section;
00841     int error_count;
00842 
00843     /* Initialize error count */
00844     error_count = 0;
00845 
00846     /* Scan every section in the md for errors */
00847     for (symbol = md->section_table->head_symbol; symbol != NULL;
00848          symbol = symbol->next_symbol)
00849     {
00850         /* Get the section pointed to by this symbol */
00851         section = (MD_Section *) symbol->data;
00852 
00853         /* Sum up all the errors found by check section */
00854         error_count += _MD_check_section (out, section, "MD_check_md");
00855     }
00856 
00857     /* Return the number of errors found in the md */
00858     return (error_count);
00859 }
00860 
00861 
00862 /* Creates a md buf for the MD_read routines */
00863 MD_Buf *MD_new_buf ()
00864 {
00865     MD_Buf *buf;
00866     int buf_size;
00867 
00868     /* Allocate new buf */
00869     buf = (MD_Buf *) L_alloc (MD_Buf_pool);
00870 
00871     /* Create a initial buffer of size 128 */
00872     buf_size = 128;
00873     buf->buf = (char *) malloc (buf_size);
00874     if (buf->buf == NULL)
00875         MD_punt (NULL, "MD_new_buf: out of memory (size %i)", buf_size);
00876     buf->buf_size = buf_size;
00877 
00878     /* Return the new buffer */
00879     return (buf);
00880 }
00881 
00882 /* Doubles the size of the buffer in buf */
00883 void MD_resize_buf (MD_Buf *buf)
00884 {
00885     char *old_buf, *new_buf;
00886     int old_size, new_size, i;
00887 
00888     /* Get fields into local variables for ease of use */
00889     old_buf = buf->buf;
00890     old_size = buf->buf_size;
00891 
00892     /* Double buffer size */
00893     new_size = old_size << 1;
00894     
00895     new_buf = (char *) malloc (new_size);
00896     if (new_buf == NULL)
00897         MD_punt (NULL, "MD_resize_buf: out of memory (size %i)", new_size);
00898     
00899     /* Copy over contents of old buffer */
00900     for (i=0; i < old_size; i++)
00901         new_buf[i] = old_buf[i];
00902     
00903     /* Free old buf and reset structure variables */
00904     free (old_buf);
00905     buf->buf = new_buf;
00906     buf->buf_size = new_size;
00907 }
00908 
00909 /* Frees md buf used by MD_read routines */
00910 void MD_delete_buf (MD_Buf *buf)
00911 {
00912     /* Free buffer */
00913     free (buf->buf);
00914 
00915     /* Free buffer structure */
00916     L_free (MD_Buf_pool, buf);
00917 }
00918 
00919 /* Reads an hex integer and returns the value. 
00920  * Uses fast conversion algorithm that assumes ascii and that all the
00921  * integers written in MD_write_md are in lower-case hex.
00922  */
00923 int MD_read_int (FILE *in)
00924 {
00925     int value, ch, negate;
00926     unsigned int nibble;
00927     
00928     /* Skip leading whitespace */
00929     while ((ch = getc(in)) != EOF)
00930     {
00931         if (ch != ' ')
00932             break;
00933     }
00934    
00935     /* Punt if hit EOF */
00936     if (ch == EOF)
00937         MD_punt (NULL, "MD_read_int: unexpected EOF");
00938 
00939     /* Is value negative? */
00940     negate = 0;
00941     if (ch == '-')
00942     {
00943         negate = 1;
00944         if ((ch = getc(in)) == EOF)
00945         MD_punt (NULL, "MD_read_int: unexpected EOF");
00946     }
00947 
00948     /* Get the first nibble, assume ascii and using 'a' thru 'f'*/
00949     if (ch >= 'a')
00950         nibble = 10 + ch - 'a';
00951     else
00952         nibble = ch - '0';
00953 
00954     /* Make sure in range */
00955     if (nibble > 15)
00956         MD_punt (NULL, "MD_read_int: int expected not '%c'", ch);
00957         
00958     /* Initially set value to this */
00959     value = nibble;
00960     
00961     /* Read in rest of int */
00962     while ((ch = getc(in)) != EOF)
00963     {
00964         /* Stop at space or newline */
00965         if ((ch == ' ') || (ch == '\n'))
00966             break;
00967 
00968         /* Get the next nibble, assume ascii and using 'a' thru 'f'*/
00969         if (ch >= 'a')
00970             nibble = 10 + ch - 'a';
00971         else
00972             nibble = ch - '0';
00973 
00974         /* Make sure in range */
00975         if (nibble > 15)
00976             MD_punt (NULL, "MD_read_int: int expected not '%c'", ch);
00977 
00978         /* Shift value and add in nibble */
00979         value = (value << 4) + nibble;
00980     }
00981 
00982     /* If not at EOF, put back character just read */
00983     if (ch != EOF)
00984         ungetc (ch, in);
00985 
00986     /* Negate value if necessary */
00987     if (negate)
00988         value = -value;
00989 
00990     /* Return value read in */
00991     return (value);
00992 }
00993 
00994 /* Reads an double into buf and returns its value (contents of buf destroyed)
00995  */
00996 double MD_read_double (FILE *in, MD_Buf *value_buf)
00997 {
00998     char *buf, *end_ptr;
00999     int i, ch, resize_size;
01000     double value;
01001     
01002     /* Get values in value_buf into local variables for ease of access */
01003     buf = value_buf->buf;
01004     resize_size = value_buf->buf_size -2; /* Want space for terminator */
01005 
01006     /* Skip leading whitespace */
01007     while ((ch = getc(in)) != EOF)
01008     {
01009         if (ch != ' ')
01010             break;
01011     }
01012    
01013     /* Punt if hit EOF */
01014     if (ch == EOF)
01015         MD_punt (NULL, "MD_read_double: unexpected EOF");
01016 
01017     /* Place first character of in buffer */
01018     buf[0] = ch;
01019     i = 1;
01020 
01021     /* Read in rest of double */
01022     while ((ch = getc(in)) != EOF)
01023     {
01024         /* Stop at space or newline */
01025         if ((ch == ' ') || (ch == '\n'))
01026             break;
01027         
01028         /* Resize buffer if necessary */
01029         if (i >= resize_size)
01030         {
01031             MD_resize_buf (value_buf);
01032 
01033             /* Get new values into local variables */
01034             buf = value_buf->buf;
01035             resize_size = value_buf->buf_size -2;
01036         }
01037 
01038         buf[i] = ch;
01039         i++;
01040     }
01041 
01042     /* If not at EOF, put back character just read */
01043     if (ch != EOF)
01044         ungetc (ch, in);
01045 
01046     /* Terminate buffer */
01047     buf[i] = 0;
01048 
01049     /* Get the double value */
01050     value = strtod (buf, &end_ptr);
01051 
01052     /* Make sure read in something */
01053     if (*end_ptr != 0)
01054         MD_punt (NULL, "MD_read_double: double expected not '%s'!", buf);
01055 
01056     /* Return value read in */
01057     return (value);
01058 }
01059 
01060 /* Reads an string into buf (value returned in buf) */
01061 void MD_read_string (FILE *in, MD_Buf *value_buf)
01062 {
01063     char *buf;
01064     int  i, ch, resize_size;
01065     
01066     /* Get values in value_buf into local variables for ease of access */
01067     buf = value_buf->buf;
01068     resize_size = value_buf->buf_size -2; /* Want space for terminator */
01069 
01070     /* Dont skip leading whitespace */
01071    
01072     i = 0;
01073 
01074     /* Read in string */
01075     while ((ch = getc(in)) != EOF)
01076     {
01077         /* Stop at newline only (spaces can be part of the string) */
01078         if (ch == '\n')
01079             break;
01080         
01081         /* Resize buffer if necessary */
01082         if (i >= resize_size)
01083         {
01084             MD_resize_buf (value_buf);
01085 
01086             /* Get new values into local variables */
01087             buf = value_buf->buf;
01088             resize_size = value_buf->buf_size -2;
01089         }
01090 
01091         buf[i] = ch;
01092         i++;
01093     }
01094 
01095     /* If not at EOF, put back character just read */
01096     if (ch != EOF)
01097         ungetc (ch, in);
01098     /* Make sure not at EOF with empty buffer */
01099     else if (i == 0)
01100         MD_punt (NULL, "MD_read_string: unexpected EOF");
01101 
01102     /* Terminate buffer, value returned in value_buffer (buf)*/
01103     buf[i] = 0;
01104 }
01105 
01106 void MD_read_nl (FILE *in)
01107 {
01108     int ch;
01109 
01110     ch = getc (in);
01111     if (ch != '\n')
01112     {
01113         if (ch == EOF)
01114             MD_punt (NULL, "MD_read_nl: unexpected EOF");
01115 
01116         MD_punt (NULL, "MD_read_nl: newline expected not '%c'!", ch);
01117     }
01118 }
01119 
01120 void MD_read_sp (FILE *in)
01121 {
01122     int ch;
01123 
01124     ch = getc (in);
01125     if (ch != ' ')
01126     {
01127         if (ch == EOF)
01128             MD_punt (NULL, "MD_read_sp: unexpected EOF");
01129 
01130         MD_punt (NULL, "MD_read_sp: space expected not '%c'!", ch);
01131     }
01132 }
01133 
01134 /* Creates a md from the low-level format file created by MD_write_md */
01135 MD *MD_read_md (FILE *in, char *name)
01136 {
01137     MD *md;
01138     MD_Section *section, **section_array, **target_array;
01139     MD_Entry *entry, **entry_array, *link;
01140     MD_Field_Decl *field_decl, **field_decl_array;
01141     MD_Buf *name_buf, *value_buf;
01142     MD_Field *field;
01143     int section_array_size, entry_array_size;
01144     int section_index, entry_index, field_decl_index;
01145     int entry_count, field_decl_count;
01146     char type_marker, kleene_marker, require_marker;
01147     MD_FIELD_TYPE field_type;
01148     int kleene_starred, require_count, require_index, target_index;
01149     int target_count, local_entry_index, element_index, element_count;
01150     int field_count, field_index, int_value, link_index;
01151     double double_value;
01152     int i;
01153     
01154     /* Create buf alloc pool used by read routines */
01155     MD_Buf_pool = L_create_alloc_pool ("MD_Buf", sizeof(MD_Buf), 4);
01156 
01157     /* Create the buffers we will need to read in the md */
01158     name_buf = MD_new_buf();
01159     value_buf = MD_new_buf();
01160 
01161     /* Get the number of sections and entries */
01162     section_array_size = MD_read_int (in);
01163     entry_array_size = MD_read_int (in);
01164     MD_read_nl (in);
01165     MD_read_nl (in);
01166 
01167     /* Create md */
01168     md = MD_new_md (name, section_array_size);
01169     
01170 /*    printf ("section_array_size = %i   entry_array_size = %i\n",
01171             section_array_size, entry_array_size); */
01172 
01173     /* Allocate section and entry arrays */
01174     section_array = (MD_Section **) malloc (sizeof(MD_Section *) * 
01175                                             section_array_size);
01176     if (section_array == NULL)
01177     {
01178         MD_punt (NULL, "MD_read_md: out of memory (size %i).",
01179                  section_array_size);
01180     }
01181 
01182     entry_array = (MD_Entry **) malloc (sizeof(MD_Entry *) * 
01183                                             entry_array_size);
01184     if (entry_array == NULL)
01185     {
01186         MD_punt (NULL, "MD_read_md: out of memory (size %i).",
01187                  entry_array_size);
01188     }
01189 
01190     /* Initialize entry index */
01191     entry_index = 0;
01192 
01193     /* Read in each section and the section's entry names */
01194     for (section_index = 0; section_index < section_array_size; 
01195          section_index++)
01196     {
01197         /* Read in section name, entry count and field decl count */
01198         MD_read_string (in, name_buf);
01199         MD_read_nl(in);
01200 
01201         entry_count = MD_read_int (in);
01202         field_decl_count = MD_read_int (in);
01203         MD_read_nl(in);
01204 
01205 /*      printf ("Read %s %i %i\n", name_buf->buf, entry_count, 
01206                 field_decl_count);*/
01207 
01208         /* Create section and put in section array */
01209         section = MD_new_section (md, name_buf->buf, entry_count, 
01210                                   field_decl_count);
01211         section_array[section_index] = section;
01212 
01213         /* Read in section's entry names */
01214         for (i = 0; i < entry_count; i++)
01215         {
01216             MD_read_string (in, name_buf);
01217             MD_read_nl (in);
01218 
01219             /* Create entry and put in entry array */
01220             entry = MD_new_entry (section, name_buf->buf);
01221             entry_array[entry_index++] = entry;
01222         }
01223         MD_read_nl(in);
01224     }
01225     MD_read_nl(in);
01226 
01227     /* Restart entry index for reading in all the entry's fields */
01228     entry_index = 0;
01229     
01230     /* Read in each section's field declarations and the
01231      * field values for all entries in the section.
01232      */
01233     for (section_index = 0; section_index < section_array_size; 
01234          section_index++)
01235     {
01236         /* Read in section name, entry count and field decl count */
01237         MD_read_string (in, name_buf);
01238 /*      printf ("Reading section %s\n", name_buf->buf); */
01239         MD_read_nl(in);
01240 
01241         entry_count = MD_read_int (in);
01242         field_decl_count = MD_read_int (in);
01243         MD_read_nl(in);
01244 
01245         /* Get the section we expect to be in */
01246         section = section_array[section_index];
01247 
01248         /* Make sure the name matches the name read in */
01249         if (strcmp (name_buf->buf, section->name) != 0)
01250         {
01251             MD_punt (NULL, "Section '%s' expected, not '%s'!",
01252                      section->name, name_buf->buf);
01253         }
01254 
01255         /* Create array only if there are field declarations */
01256         if (field_decl_count > 0)
01257         {
01258             /* Create field declaration array */
01259             field_decl_array = 
01260                 (MD_Field_Decl **) malloc (sizeof(MD_Field_Decl *) *
01261                                            field_decl_count);
01262             if (field_decl_array == NULL)
01263                 MD_punt (NULL, "MD_read_md: Out of memory (size %i)", 
01264                          field_decl_count);
01265         }
01266         else
01267         {
01268             /* Should not be used if there are no field declarations */
01269             field_decl_array = NULL;
01270         }
01271 
01272         /* Read in the field declarations */
01273         for (field_decl_index = 0; field_decl_index < field_decl_count;
01274              field_decl_index++)
01275         {
01276             /* Get field name */
01277             MD_read_string (in, name_buf);
01278 /*          printf ("Declaring field '%s'\n", name_buf->buf); */
01279             MD_read_nl (in);
01280 
01281             /* Get type of field declaration */
01282             type_marker = getc (in);
01283 
01284             switch (type_marker)
01285             {
01286               case 'R':
01287                 field_type = MD_REQUIRED_FIELD;
01288                 break;
01289 
01290               case 'O':
01291                 field_type = MD_OPTIONAL_FIELD;
01292                 break;
01293 
01294               default:
01295                 MD_punt (NULL, "MD_read_md: Unknown field decl type '%c'",
01296                          type_marker);
01297             }
01298 
01299             require_count = MD_read_int(in);
01300             MD_read_sp (in);
01301             kleene_marker = getc (in);
01302 
01303             switch (kleene_marker)
01304             {
01305               case '*':
01306                 kleene_starred = 1;
01307                 break;
01308 
01309               case '-':
01310                 kleene_starred = 0;
01311                 break;
01312 
01313               default:
01314                 MD_punt (NULL, "MD_read_md: Unknown kleene marker '%c'",
01315                          kleene_marker);
01316             }
01317             MD_read_nl (in);
01318 
01319             /* Create field declaration and place into array */
01320             field_decl = MD_new_field_decl (section, name_buf->buf,
01321                                             field_type);
01322             field_decl_array[field_decl_index] = field_decl;
01323 
01324 /*          printf ("Read field_decl %s\n", name_buf->buf); */
01325             
01326             /* Read in requirements */
01327             for (require_index = 0; require_index < require_count;
01328                  require_index++)
01329             {
01330                 /* Get requirement type */
01331                 require_marker = getc (in);
01332 
01333                 /* Define requirment */
01334                 switch (require_marker)
01335                 {
01336                   case 'I':
01337                     MD_require_int (field_decl, require_index);
01338                     break;
01339 
01340                   case 'D':
01341                     MD_require_double (field_decl, require_index);
01342                     break;
01343 
01344                   case 'S':
01345                     MD_require_string (field_decl, require_index);
01346                     break;
01347 
01348                   case 'L':
01349                     /* Get the number of targets */
01350                     target_count = MD_read_int (in);
01351 
01352                     /* Create target array */
01353                     target_array = 
01354                         (MD_Section **) malloc (sizeof(MD_Section *) *
01355                                                 target_count);
01356                     
01357                     if (target_array == NULL)
01358                     {
01359                         MD_punt (NULL, "MD_read_md: Out of memory (size %i)",
01360                                  target_count);
01361                     }
01362 
01363                     /* Read in targets */
01364                     for (i=0; i < target_count; i++)
01365                     {
01366                         target_index = MD_read_int (in);
01367                         target_array[i] = section_array[target_index];
01368                     }
01369 
01370                     MD_require_multi_target_link (field_decl, require_index,
01371                                                   target_count, target_array);
01372 
01373                     /* Free target array */
01374                     free (target_array);
01375 
01376                     break;
01377                     
01378                   default:
01379                     MD_punt (NULL, 
01380                              "MD_read_md: Unknown requirement type '%c'", 
01381                             require_marker);
01382 
01383                 }
01384                 MD_read_nl(in);
01385 
01386             }
01387             MD_read_nl(in);
01388 
01389             /* Mark last requirement as kleene starred (if required) */
01390             if (kleene_starred)
01391             {
01392                 MD_kleene_star_requirement (field_decl, require_count -1);
01393             }
01394         }
01395         /* Read in the fields for each entry */
01396         for (local_entry_index = 0; local_entry_index < entry_count;
01397              local_entry_index++)
01398         {         
01399             /* Get the entry we are processing, use entry_index
01400              * to get entry id from start of md (not from start
01401              * of section)
01402              */
01403             entry = entry_array[entry_index++];
01404             
01405             /* Read the number of fields defined */
01406             field_count = MD_read_int (in);
01407             MD_read_nl (in);
01408             MD_read_nl (in);
01409             
01410             /* Read in the fields defined */
01411             for (i = 0; i < field_count; i++)
01412             {
01413                 /* Get the field index and field decl for this index */
01414                 field_index = MD_read_int (in);
01415                 element_count = MD_read_int (in);
01416                 MD_read_nl (in);
01417 
01418                 field_decl = field_decl_array[field_index];
01419                 
01420 /*              printf ("Reading field %s\n", field_decl->name); */
01421 
01422                 /* Create field */
01423                 field = MD_new_field (entry, field_decl, element_count);
01424 
01425                 /* Read in the elements */
01426                 for (element_index = 0; element_index < element_count;
01427                      element_index++)
01428                 {
01429                     /* Get the type of element */
01430                     type_marker = getc(in);
01431 
01432                     /* Read in depending on type */
01433                     switch (type_marker)
01434                     {
01435                       case 'I':
01436                         int_value = MD_read_int (in);
01437                         MD_set_int (field, element_index, int_value);
01438                         break;
01439 
01440                       case 'D':
01441                         double_value = MD_read_double (in, value_buf);
01442                         MD_set_double (field, element_index, double_value);
01443                         break;
01444 
01445                       case 'S':
01446                         MD_read_string (in, value_buf);
01447                         MD_set_string (field, element_index, value_buf->buf);
01448                         break;
01449 
01450                       case 'L':
01451                         link_index = MD_read_int (in);
01452                         link = entry_array[link_index];
01453                         MD_set_link (field, element_index, link);
01454                         break;
01455 
01456                       default:
01457                         MD_punt (NULL, "MD_read_md: Uknown element type '%c'.",
01458                                  type_marker);
01459                     }
01460                     MD_read_nl(in);
01461                 }
01462                 MD_read_nl(in);
01463             }
01464         }
01465         MD_read_nl(in);
01466 
01467         /* Free field_decl_array */
01468         if (field_decl_array != NULL)
01469             free (field_decl_array);
01470     }
01471 
01472     /* Free arrays we created for reading in md */
01473     free (section_array);
01474     free (entry_array);
01475 
01476 
01477     /* Free the buffers we created */
01478     MD_delete_buf (name_buf);
01479     MD_delete_buf (value_buf);
01480 
01481     /* Free the buf alloc pool */
01482     L_free_alloc_pool (MD_Buf_pool);
01483 
01484     /* Return the md created */
01485     return (md);
01486 }
01487 
01488 
01489 
01490 /* Writes the md's contents to the file in the low-level format
01491  * that MD_read_md() expects.
01492  */
01493 void MD_write_md (FILE *out, MD *md)
01494 {
01495     MD_Symbol *section_symbol, *entry_symbol, *field_decl_symbol;
01496     MD_Section *section, **link_array;
01497     MD_Entry *entry;
01498     MD_Field_Decl *field_decl;
01499     MD_Element_Req *element_req, **require_array;
01500     MD_Field **field_array, *field;
01501     MD_Element *element, **element_array;
01502     int total_entry_count, max_require_index, i;
01503     int section_id, entry_id, field_decl_id, link_array_size;
01504     int max_field_index, field_count, max_assigned_index, require_index;
01505     char type_marker, kleene_marker;
01506 
01507     /* Initialize the total number of entries in the md */
01508     total_entry_count = 0;
01509 
01510     /* Initialize the seciton and entry id counters.  */
01511     section_id = 0;
01512     entry_id = 0;
01513 
01514     /* Scan entire md, assigning ids to all the symbols */
01515     for (section_symbol = md->section_table->head_symbol; 
01516          section_symbol != NULL; section_symbol = section_symbol->next_symbol)
01517     {
01518         /* Set the section symbol id */
01519         section_symbol->symbol_id = section_id++;
01520 
01521         /* Get the section for ease of use */
01522         section = (MD_Section *) section_symbol->data;
01523 
01524         /* Set the field_ids for all fields declared for this section.
01525          * Starts from 0 at the beginning of each section.
01526          */
01527         field_decl_id = 0;
01528         for (field_decl_symbol = section->field_decl_table->head_symbol;
01529              field_decl_symbol != NULL; 
01530              field_decl_symbol = field_decl_symbol->next_symbol)
01531         {
01532             field_decl_symbol->symbol_id = field_decl_id++;
01533         }
01534 
01535 
01536         /* Set the symbol_ids for all entries in this table.
01537          * Starts from 0 at beginning of md to give each entry
01538          * a unique id.
01539          */
01540         for (entry_symbol = section->entry_table->head_symbol;
01541              entry_symbol != NULL; entry_symbol = entry_symbol->next_symbol)
01542         {
01543             entry_symbol->symbol_id = entry_id++;
01544         }
01545 
01546         /* Update the total entry count */
01547         total_entry_count += section->entry_table->symbol_count;
01548     }
01549 
01550     /* Write out how many sections and entries in the md */
01551     fprintf (out, "%x %x\n\n", md->section_table->symbol_count,
01552              total_entry_count);
01553 
01554     /* Write out the header for each section and list out the
01555      * entries in each section.
01556      */
01557     for (section_symbol = md->section_table->head_symbol; 
01558          section_symbol != NULL; section_symbol = section_symbol->next_symbol)
01559     {
01560         /* Get the section for ease of use */
01561         section = (MD_Section *) section_symbol->data;
01562 
01563         /* Write out each section name and how many entries the section
01564          * has and how many fields are declared for the section.
01565          */
01566 #if 0
01567         fprintf (out, "%i %s %i %i\n", section_symbol->symbol_id, 
01568                  section->name,
01569                  section->entry_table->symbol_count, 
01570                  section->field_decl_table->symbol_count);
01571 #endif
01572         fprintf (out, "%s\n%x %x\n", 
01573                  section->name,
01574                  section->entry_table->symbol_count, 
01575                  section->field_decl_table->symbol_count);
01576 
01577         for (entry_symbol = section->entry_table->head_symbol;
01578              entry_symbol != NULL; entry_symbol = entry_symbol->next_symbol)
01579         {
01580             /* Get the entry for ease of use */
01581             entry = (MD_Entry *) entry_symbol->data;
01582 
01583             /* Write out each entries name */
01584 #if 0
01585             fprintf (out, "%i %s\n", entry_symbol->symbol_id,
01586                      entry->name);
01587 #endif
01588             fprintf (out, "%s\n", entry->name);
01589 
01590         }
01591 
01592         putc ('\n', out);
01593     }
01594     putc ('\n', out);
01595 
01596     /*
01597      * Write out the section's contents
01598      */
01599     for (section_symbol = md->section_table->head_symbol; 
01600          section_symbol != NULL; section_symbol = section_symbol->next_symbol)
01601     {
01602         /* Get the section for ease of use */
01603         section = (MD_Section *) section_symbol->data;
01604 
01605         /* Again write how many entries and field declarations there
01606          * are in the section 
01607          */
01608 #if 0
01609         fprintf (out, "%i %s %i %i\n", section_symbol->symbol_id,
01610                  section->name, 
01611                  section->entry_table->symbol_count,
01612                  section->field_decl_table->symbol_count);
01613 #endif
01614         fprintf (out, "%s\n%x %x\n",
01615                  section->name, 
01616                  section->entry_table->symbol_count,
01617                  section->field_decl_table->symbol_count);
01618 
01619         for (field_decl_symbol = section->field_decl_table->head_symbol;
01620              field_decl_symbol != NULL; 
01621              field_decl_symbol = field_decl_symbol->next_symbol)
01622         {
01623             /* Get the field declaration from the symbol */
01624             field_decl = (MD_Field_Decl *) field_decl_symbol->data;
01625 
01626             switch (field_decl->type)
01627             {
01628               case MD_REQUIRED_FIELD:
01629                 type_marker = 'R';
01630                 break;
01631 
01632               case MD_OPTIONAL_FIELD:
01633                 type_marker = 'O';
01634                 break;
01635 
01636               default:
01637                 MD_punt (NULL, "MD_write_md: Unknown field decl type '%i'.",
01638                          field_decl->type);
01639             }
01640 
01641             if (field_decl->kleene_starred_req != NULL)
01642                 kleene_marker = '*';
01643             else
01644                 kleene_marker = '-';
01645 
01646 
01647             /* Get values into local variables for ease of use */
01648             max_require_index = field_decl->max_require_index;
01649             require_array = field_decl->require;
01650             
01651             /* Print out the field name and the number of
01652              * required fields
01653              */
01654 #if 0
01655             fprintf (out, "%i %s %i %c\n", field_decl_symbol->symbol_id,
01656                      field_decl->name, 
01657                      max_require_index + 1,
01658                      kleene_marker);
01659 #endif
01660             fprintf (out, "%s\n%c %x %c\n", 
01661                      field_decl->name,
01662                      type_marker,
01663                      max_require_index + 1,
01664                      kleene_marker);
01665 
01666             for (require_index=0; require_index <= max_require_index; 
01667                  require_index++)
01668             {
01669                 element_req = require_array[require_index];
01670                 
01671                 switch (element_req->type)
01672                 {
01673                   case MD_INT:
01674                     putc ('I', out);
01675                     putc ('\n', out);
01676                     break;
01677 
01678                   case MD_DOUBLE:
01679                     putc ('D', out);
01680                     putc ('\n', out);
01681                     break;
01682 
01683                   case MD_STRING:
01684                     putc ('S', out);
01685                     putc ('\n', out);
01686                     break;
01687 
01688                   case MD_LINK:
01689                     link_array = element_req->link;
01690                     link_array_size = element_req->link_array_size;
01691                     fprintf (out, "L %x", link_array_size);
01692                     for (i=0; i < link_array_size; i++)
01693                         fprintf (out, " %x", link_array[i]->symbol->symbol_id);
01694                     putc ('\n', out);
01695                     break;
01696                     
01697                   default:
01698                     MD_punt (NULL, "MD_write_md: Unknown req type %i",  
01699                              element_req->type);
01700                 }
01701 
01702             }
01703             putc ('\n', out);
01704         }
01705 
01706         /* Get values into local variables for ease of use */
01707         max_field_index = section->max_field_index;
01708         
01709         /* Print out the field contents for each field */
01710         for (entry_symbol = section->entry_table->head_symbol;
01711              entry_symbol != NULL; 
01712              entry_symbol = entry_symbol->next_symbol)
01713         {
01714             /* Get the entry for ease of use */
01715             entry = (MD_Entry *) entry_symbol->data;
01716             
01717             /* Get the field array for ease of use */
01718             field_array = entry->field;
01719             
01720             /* Count the number of fields defined for this entry */
01721             field_count = 0;
01722             for (i=0; i <= max_field_index; i++)
01723             {
01724                 if (field_array[i] != NULL)
01725                     field_count ++;
01726             }
01727             
01728             /* Write out header for each entry, specifying the
01729              * number of fields defined for each entry
01730              */
01731 #if 0
01732             fprintf (out, "%i %i\n", entry_symbol->symbol_id,
01733                      field_count);
01734 #endif
01735 
01736             fprintf (out, "%x\n\n", field_count);
01737             
01738             for (field_decl_symbol=section->field_decl_table->head_symbol;
01739                  field_decl_symbol != NULL; 
01740                  field_decl_symbol = field_decl_symbol->next_symbol)
01741             {
01742                 /* Get the field declaration from the symbol */
01743                 field_decl = (MD_Field_Decl *) field_decl_symbol->data;
01744                 
01745                 field = field_array[field_decl->field_index];
01746                 
01747                 if (field == NULL)
01748                     continue;
01749 
01750                 /* Get element array for ease of use */
01751                 element_array = field->element;
01752 
01753                 /* Find the max assigned element index */
01754                 for (max_assigned_index = field->max_element_index;
01755                      max_assigned_index >= 0; max_assigned_index--)
01756                 {
01757                     if (element_array[max_assigned_index] != NULL)
01758                         break;
01759                 }
01760                 
01761                 /* Print out field header, specifying field symbol id,
01762                  * and the number of elements specified
01763                  */
01764                 fprintf (out, "%x %x\n", 
01765                          field_decl_symbol->symbol_id,
01766                          max_assigned_index + 1);
01767 
01768                 for (i=0; i <= max_assigned_index; i++)
01769                 {
01770                     /* Get element for ease of use */
01771                     element = element_array[i];
01772 
01773                     if (element == NULL)
01774                     {
01775                         fprintf (out, "-\n");
01776                     }
01777                     else
01778                     {
01779                         switch (element->type)
01780                         {
01781                             /* Print int elements as signed hex numbers */
01782                           case MD_INT:
01783                             if (element->value.i < 0)
01784                                 fprintf (out, "I-%x\n", -element->value.i);
01785                             else
01786                                 fprintf (out, "I%x\n", element->value.i);
01787 
01788                             break;
01789 
01790                           case MD_DOUBLE:
01791                             fprintf (out, "D%0.16g\n", element->value.d);
01792                             break;
01793 
01794                           case MD_STRING:
01795                             fprintf (out, "S%s\n", element->value.s);
01796                             break;
01797 
01798                           case MD_LINK:
01799                             fprintf (out, "L%x\n",
01800                                      element->value.l->symbol->symbol_id);
01801                             break;
01802 
01803                           default:
01804                             MD_punt (NULL, 
01805                                      "MD_write_md: Unknown element type %i.",
01806                                      element->type);
01807                         }
01808                     }
01809                 }
01810                 
01811                 putc ('\n', out);
01812             }
01813         }
01814         
01815         putc ('\n', out);
01816         
01817     }
01818     putc('\n', out);
01819 }
01820 
01821 /* Prints the md's contents to out in text format */
01822 void MD_print_md (FILE *out, MD *md, int page_width)
01823 {
01824     MD_Section *section;
01825     MD_Symbol *symbol;
01826 
01827     /* Print header for this md (as comment) */
01828     fprintf (out, "/*\n * %s:\n", md->name);
01829     fprintf (out, 
01830              " *    Field declarations and entry contents for each section\n");
01831     fprintf (out, " */");
01832 
01833     /* Print out each section in the md */
01834     for (symbol = md->section_table->head_symbol; symbol != NULL;
01835          symbol = symbol->next_symbol)
01836     {
01837         /* Get the section for ease of use */
01838         section = (MD_Section *) symbol->data;
01839 
01840         putc ('\n', out);
01841 
01842         /* Print out the section */
01843         MD_print_section (out, section, page_width);
01844     }
01845 }
01846 
01847 /*
01848  * Prints the section and entry declarations required to make the output of 
01849  * MD_print_md a valid hmdes file.  These declarations resolve the 
01850  * problem of circular LINKs that can occur between entries in md files.   
01851  * Print out all sections and entries (verses the minimum subset required)
01852  * to preserve section and entry order in md.
01853  * 
01854  * Print in a compact format since these declarationcs are not very 
01855  * informative.
01856  */
01857 void MD_print_md_declarations (FILE *out, MD *md, int page_width)
01858 {
01859     MD_Section *section;
01860     MD_Entry *entry, *next_entry;
01861     char *entry_name;
01862     int col, legal_ident, name_len;
01863     int comment_indent, cur_indent;
01864 
01865 
01866     /* Print header for this md (as comment) */
01867     fprintf (out, 
01868              "/*\n * %s:\n",
01869              md->name);
01870     fprintf (out, 
01871              " *   Declaration of all section and entry names\n */");
01872 
01873     /* Determine where to print the '// Declaration' comment. 
01874      * Put it near column 39 unless page_width is too narrow.
01875      */
01876     comment_indent = 39;
01877     if (comment_indent > (page_width - 16))
01878         comment_indent = page_width - 16;
01879 
01880     /* Create each section in order */
01881     for (section = MD_first_section (md); section != NULL;
01882          section = MD_next_section (section))
01883     {
01884         fprintf (out, "\nCREATE SECTION %s",
01885                  section->name);
01886 
01887         /* Calculate current indentation */
01888         cur_indent = 15 + strlen (section->name);
01889 
01890         /* Pad with spaces */
01891         while (cur_indent < comment_indent)
01892         {
01893             putc (' ', out);
01894             cur_indent++;
01895         }
01896 
01897         /* Print comment */
01898         fprintf (out, " // Declaration\n");
01899         fprintf (out, "{\n");
01900 
01901         /* Start out in column 0 */
01902         col = 0;
01903 
01904         /* Declare all the entries in each section */
01905         for (entry = MD_first_entry (section); entry != NULL;
01906              entry = next_entry)
01907         {
01908             /* Get next entry now for newline processing later */
01909             next_entry = MD_next_entry (entry);
01910 
01911             /* Get entry name for ease of use */
01912             entry_name = entry->name;
01913 
01914             /* Get length of name */
01915             name_len = strlen (entry_name);
01916 
01917             /* Is it a legal identifier? */
01918             legal_ident = MD_legal_ident (entry_name);
01919 
01920             /* If not a legal identifier, name will be two characters longer */
01921             if (!legal_ident)
01922                 name_len += 2;
01923 
01924             /* Do we need to go to a newline before we print this name?
01925              * (yes if not at beginning of line and will go past page_width)
01926              */
01927             if ((col != 0) && (col + name_len + 4) >= page_width)
01928             {
01929                 putc ('\n', out);
01930                 col = 0;
01931             }
01932 
01933             /* Put extra space at beginning of each line */
01934             if (col == 0)
01935             {
01936                 putc (' ', out);
01937                 col = 1;
01938             }
01939 
01940             /* Print out the entry name (with quotes if not a legal ident) */
01941             if (!MD_legal_ident(entry_name))
01942             {
01943                 fprintf (out, " '%s'();", entry_name);
01944             }
01945             else
01946             {
01947                 fprintf (out, " %s();", entry_name);
01948             }
01949             col += name_len + 4;
01950 
01951         }
01952         
01953         putc ('\n', out);
01954         putc ('}', out);
01955         putc ('\n', out);
01956     }
01957 
01958     
01959 
01960 }
01961 
01962 /* Prints the section and entry names in the md */
01963 void MD_print_md_template (FILE *out, MD *md)
01964 {
01965     MD_Section *section;
01966     MD_Symbol *symbol;
01967     int first_section;
01968 
01969     /* Print header for this md (as comment) */
01970     fprintf (out, "/*\n * %s template\n */\n", md->name);
01971 
01972     /* Mark that we are about to print out the first section */
01973     first_section = 1;
01974 
01975     /* Print out each section in the md */
01976     for (symbol = md->section_table->head_symbol; symbol != NULL;
01977          symbol = symbol->next_symbol)
01978     {
01979         /* Get the section for ease of use */
01980         section = (MD_Section *) symbol->data;
01981 
01982         /* Print a newline before the section if not the first section */
01983         if (!first_section)
01984             putc ('\n', out);
01985 
01986         /* Otherwise, mark that next section is not the first section */
01987         else
01988             first_section = 0;
01989 
01990         /* Print out the section name and section entry's names*/
01991         MD_print_section_template (out, section);
01992     }
01993 }
01994 
01995 
01996 /* Creates a new section in the md with an initial size suitable for the 
01997  * specified number of entries and number of fields.  The section 
01998  * automatically resizes (upward) when appropriate, so 0 entries and/or
01999  * 0 may be specified.
02000  */
02001 MD_Section *MD_new_section (MD *md, char *name, int num_entries, 
02002                             int num_fields)
02003 {
02004     MD_Section *section;
02005     char *field_decl_desc, *entry_desc;
02006 
02007     /* Allocate a new section structure */
02008     section = (MD_Section *) L_alloc (MD_Section_pool);
02009 
02010     /* Initialize the section's fields */
02011     section->md = md;
02012     section->name = strdup (name);
02013 
02014     /* Initialize user's extension pointer to NULL */
02015     section->user_ext = NULL;
02016 
02017     /* Create a symbol table for this section's entries.
02018      * Create a good description, so symbol table error messages
02019      * (such as two symbol's with same name) are intelligible.
02020      */
02021     entry_desc = MD_concat_strings (name, "'s entry table");
02022     section->entry_table = MD_new_symbol_table (md, entry_desc, num_entries);
02023     free (entry_desc);
02024 
02025 
02026     /* Create a symbol table for this section's field declarations.
02027      * Create a good description, so symbol table error messages
02028      * (such as two symbol's with same name) are intelligible.
02029      */
02030     field_decl_desc = MD_concat_strings (name, "'s field declaration table");
02031     section->field_decl_table = MD_new_symbol_table (md, field_decl_desc, 
02032                                                         num_fields);
02033     free (field_decl_desc);
02034 
02035     /* Initialize field decl fields to 0 fields then resize using
02036      * num_fields to get intial size specified in num_fields.
02037      */
02038     section->max_field_index = -1;
02039     section->field_decl = NULL;
02040     section->field_array_size = 0;
02041 
02042     /* Resize the array based on num_fields unless num_fields is specified
02043      * as 0.  (The entry_table must be built before this is called).
02044      */
02045     if (num_fields != 0)
02046     {
02047         MD_resize_field_arrays (section, num_fields);
02048     }
02049 
02050 
02051     /* Add section to the md's section table, place pointer of added
02052      * symbol into section structure for easy access.
02053      */
02054     section->symbol =  MD_add_symbol (md->section_table, section->name, 
02055                                       (void *) section);
02056 
02057     /* Return the new section */
02058     return (section);
02059 }
02060 
02061 /*
02062  * DO NOT CALL DIRECTLY! Use macro MD_num_sections()!
02063  * This is the function version of the macro MD_num_sections().
02064  * 
02065  * Used to allow arguments to be checked for macros.
02066  */
02067 int _MD_num_sections (MD *md)
02068 {
02069     /* Return number of sections found in the md's section table */
02070     return (md->section_table->symbol_count);
02071 }
02072 
02073 /*
02074  * DO NOT CALL DIRECTLY! Use macro MD_find_section()!
02075  * This is the function version of the macro MD_find_section().
02076  * 
02077  * Used to allow arguments to be checked for macros.
02078  */
02079 MD_Section *_MD_find_section (MD *md, char *name)
02080 {
02081     /* Find section in md table, return data cast as MD_Section */
02082     return ((MD_Section *) _MD_find_symbol_data(md->section_table, name));
02083 }
02084 
02085 /*
02086  * Returns a pointer to the first section in the MD or NULL if MD empty.
02087  */
02088 MD_Section *MD_first_section (MD *md)
02089 {
02090     MD_Symbol *symbol;
02091     
02092     symbol = md->section_table->head_symbol;
02093 
02094     if (symbol != NULL)
02095         return ((MD_Section *) symbol->data);
02096     else
02097         return (NULL);
02098 }
02099 
02100 /*
02101  * Returns a pointer to the last section in the MD or NULL if MD empty.
02102  */
02103 MD_Section *MD_last_section (MD *md)
02104 {
02105     MD_Symbol *symbol;
02106     
02107     symbol = md->section_table->tail_symbol;
02108 
02109     if (symbol != NULL)
02110         return ((MD_Section *) symbol->data);
02111     else
02112         return (NULL);
02113 }
02114 
02115 /* 
02116  * Returns a pointer to the next section in the MD or NULL if passed 
02117  * a pointer to the last section in the MD.
02118  */
02119 MD_Section *MD_next_section (MD_Section *section)
02120 {
02121     MD_Symbol *symbol;
02122 
02123     symbol = section->symbol->next_symbol;
02124 
02125     if (symbol != NULL)
02126         return ((MD_Section *) symbol->data);
02127     else
02128         return (NULL);
02129 }
02130 
02131 /* 
02132  * Returns a pointer to the previous section in the MD or NULL if passed 
02133  * a pointer to the first section in the MD.
02134  */
02135 MD_Section *MD_prev_section (MD_Section *section)
02136 {
02137     MD_Symbol *symbol;
02138 
02139     symbol = section->symbol->prev_symbol;
02140 
02141     if (symbol != NULL)
02142         return ((MD_Section *) symbol->data);
02143     else
02144         return (NULL);
02145 }
02146 
02147 /*
02148  * DO NOT CALL DIRECTLY! Use macro MD_set_section_ext()! 
02149  * This is the function version of the macro MD_set_section_ext().
02150  * 
02151  * Used to allow arguments to be checked for macro.
02152  */
02153 void *_MD_set_section_ext(MD_Section *section, void *ext) 
02154 {
02155     section->user_ext = ext;
02156 
02157     /* Return ext to be equivalent to macro version */
02158     return (ext);
02159 }
02160 
02161 /*
02162  * DO NOT CALL DIRECTLY! Use macro MD_get_section_ext()!
02163  * This is the function version of the macro MD_get_section_ext().
02164  * 
02165  * Used to allow arguments to be checked for macro.
02166  */
02167 void *_MD_get_section_ext(MD_Section *section)
02168 {
02169     return (section->user_ext);   
02170 }
02171 
02172 /* 
02173  * DO NOT CALL DIRECTLY!  Use macro MD_delete_section()!
02174  * Frees the memory associated with a section.
02175  * Used by MD_delete_section macro and MD_delete_md.
02176  * 
02177  * Assumes section has already been removed from the 
02178  * md's section_table.
02179  */
02180 void _MD_free_section (MD_Section *section)
02181 {
02182     char *name;
02183 
02184     /* Free name last (for error messages) */
02185     name = section->name;
02186 
02187     /* Free entry symbol table and all the information contained in it. */
02188     MD_delete_symbol_table (section->entry_table, 
02189                             (void (*)(void *))_MD_free_entry);
02190 
02191     /* Free field declaration table and all the information contained in it.
02192      * Must be called after freeing entries because the free entry
02193      * routine uses the field declaration
02194      */
02195     MD_delete_symbol_table (section->field_decl_table, 
02196                             (void (*)(void *))_MD_free_field_decl);
02197 
02198     /* Free the field_decl array (if it exists) */
02199     if (section->field_decl != NULL)
02200         free (section->field_decl);
02201     
02202     /* Free the section structure */
02203     L_free (MD_Section_pool, section);
02204 
02205     /* Free the section's name */
02206     free (name);
02207 }
02208 
02209 /*
02210  * DO NOT CALL DIRECTLY! Use macro MD_delete_section()!
02211  * This is the function version of the macro MD_delete_section().
02212  * 
02213  * Used to allow arguments to be checked for macro.
02214  */
02215 void _MD_delete_section (MD_Section *section)
02216 {
02217     /* Delete symbol and structure memory */
02218     MD_delete_symbol (section->symbol, (void(*)(void *))_MD_free_section);
02219 }
02220 
02221 
02222 /*
02223  * DO NOT CALL DIRECTLY!  Use macro MD_check_section()!
02224  * This function checks the elements in the specified section.
02225  * Used by the MD_check_section() macro and MD_check_md().
02226  * 
02227  * Returns the number of required fields not specified + the 
02228  * number of elements with incorrect type in the section (0 if all ok).
02229  * 
02230  * If out is non-NULL, warning messages for non-specified required field
02231  * and for each element with incorrect type will be printed to out.
02232  *
02233  * The caller_name is used in the warning messages to identify the
02234  * routine/macro that started the checking process (MD_check_md or
02235  * MD_check_section).
02236  */
02237 int _MD_check_section (FILE *out, MD_Section *section, char *caller_name)
02238 {
02239     MD_Symbol *symbol;
02240     MD_Entry *entry;
02241     int error_count;
02242 
02243     /* Initialize error count */
02244     error_count = 0;
02245 
02246     /* Scan every entry in the section for errors */
02247     for (symbol = section->entry_table->head_symbol; symbol != NULL;
02248          symbol = symbol->next_symbol)
02249     {
02250         /* Get the entry pointed to by this symbol */
02251         entry = (MD_Entry *) symbol->data;
02252 
02253         /* Sum up all the errors found by check entry */
02254         error_count += _MD_check_entry (out, entry, caller_name);
02255     }
02256 
02257 
02258     /* Return the number of errors found in the section */
02259     return (error_count);
02260 }
02261 
02262 /* Prints the section's contents to out in text format */
02263 void MD_print_section (FILE *out, MD_Section *section, int page_width)
02264 {
02265     MD_Field_Decl *field_decl;
02266     MD_Symbol *symbol;
02267     MD_Entry *entry;
02268 
02269     fprintf (out, "SECTION %s\n", section->name);
02270     /* Print every field declaration in section */
02271     for (symbol = section->field_decl_table->head_symbol; symbol != NULL;
02272          symbol = symbol->next_symbol)
02273     {
02274         /* Get the field_decl pointed to by this symbol */
02275         field_decl = (MD_Field_Decl *) symbol->data;
02276 
02277         /* Print the field declaration */
02278         MD_print_field_decl (out, field_decl, page_width);
02279     }
02280     fprintf (out, "{\n");
02281 
02282     /* Print every entry in section */
02283     for (symbol = section->entry_table->head_symbol; symbol != NULL;
02284          symbol = symbol->next_symbol)
02285     {
02286         /* Get the entry pointed to by this symbol */
02287         entry = (MD_Entry *) symbol->data;
02288 
02289         /* Print the entry */
02290         MD_print_entry (out, entry, page_width);
02291     }
02292 
02293     fprintf (out, "}\n");
02294 }
02295 
02296 /* Prints the section's entry names (only) in text format */
02297 void MD_print_section_template (FILE *out, MD_Section *section)
02298 {
02299     MD_Symbol *symbol;
02300     MD_Entry *entry;
02301 
02302     fprintf (out, "SECTION %s\n{\n", section->name);
02303 
02304     /* Print every entry in section */
02305     for (symbol = section->entry_table->head_symbol; symbol != NULL;
02306          symbol = symbol->next_symbol)
02307     {
02308         /* Get the entry pointed to by this symbol */
02309         entry = (MD_Entry *) symbol->data;
02310 
02311         /* Print the entry */
02312         MD_print_entry_template (out, entry);
02313     }
02314 
02315     fprintf (out, "}\n");
02316 }
02317 
02318 /* 
02319  * Creates a new entry in a section. 
02320  */
02321 MD_Entry *MD_new_entry (MD_Section *section, char *name)
02322 {
02323     MD_Entry *entry;
02324     int field_array_size;
02325     MD_Field **field_array;
02326     int i;
02327 
02328     /* Allocate a new entry structure */
02329     entry = (MD_Entry *) L_alloc (MD_Entry_pool);
02330 
02331     /* Initialize the entry's fields */
02332     entry->section = section;
02333     entry->name = strdup (name);
02334 
02335     /* Initialize user's extension pointer to NULL */
02336     entry->user_ext = NULL;
02337 
02338     /* Get field array size from section for ease of use */
02339     field_array_size = section->field_array_size;
02340 
02341     /* Allocate field array if at least one field has been declared */
02342     if (field_array_size > 0)
02343     {
02344         field_array = (MD_Field **) malloc (sizeof(MD_Field *) * 
02345                                             field_array_size);
02346         if (field_array == NULL)
02347         {
02348             MD_punt (section->md, "MD_new_entry: Out of memory (size %i)",
02349                      field_array_size);
02350         }
02351 
02352         /* Initialize field array with NULL pointers */
02353         for (i=0; i < field_array_size; i++)
02354             field_array[i] = NULL;
02355 
02356         /* Point field at new field array */
02357         entry->field = field_array;
02358     }
02359 
02360     /* Otherwise, point field array at NULL */
02361     else
02362     {
02363         entry->field = NULL;
02364     }
02365 
02366     /* Add entry to the section's entry table, place pointer of added
02367      * symbol into entry structure for easy access.
02368      */
02369     entry->symbol =  MD_add_symbol (section->entry_table, entry->name, 
02370                                     (void *) entry);
02371 
02372     /* Return the new entry */
02373     return (entry);
02374 }
02375 
02376 /* Renames the entry but otherwise the entry is unchanged */
02377 void MD_rename_entry (MD_Entry *entry, char *new_name)
02378 {
02379     char *old_name;
02380 
02381     /* Rename entry but don't free old_name yet.  The symbol is still
02382      * pointing to the old name, and it cannot be freed until after
02383      * MD_rename_symbol!
02384      */
02385     old_name = entry->name;
02386     entry->name = strdup (new_name);
02387 
02388     /* Rename in the symbol table (will point at entry->name, not a copy) */
02389     MD_rename_symbol (entry->symbol, entry->name);
02390 
02391     /* Free old name now that it is safe to do so */
02392     free (old_name);
02393 }
02394 
02395 /*
02396  * DO NOT CALL DIRECTLY! Use macro MD_num_entries()!
02397  * This is the function version of the macro MD_num_entries().
02398  * 
02399  * Used to allow arguments to be checked for macros.
02400  */
02401 int _MD_num_entries (MD_Section *section)
02402 {
02403     /* Return number of entries found in the section's entry table */
02404     return (section->entry_table->symbol_count);
02405 }
02406 
02407 /*
02408  * DO NOT CALL DIRECTLY! Use macro MD_find_entry()!
02409  * This is the function version of the macro MD_find_entry().
02410  * 
02411  * Used to allow arguments to be checked for macros.
02412  */
02413 MD_Entry *_MD_find_entry (MD_Section *section, char *name)
02414 {
02415     /* Find entry in section table, return data cast as MD_Entry */
02416     return ((MD_Entry *) _MD_find_symbol_data(section->entry_table, name));
02417 }
02418 
02419 /*
02420  * Returns a pointer to the first entry in the section or NULL if the section
02421  * is empty.
02422  */
02423 MD_Entry *MD_first_entry (MD_Section *section)
02424 {
02425     MD_Symbol *symbol;
02426     
02427     symbol = section->entry_table->head_symbol;
02428 
02429     if (symbol != NULL)
02430         return ((MD_Entry *) symbol->data);
02431     else
02432         return (NULL);
02433 }
02434 
02435 /*
02436  * Returns a pointer to the last entry in the section or NULL if the section
02437  * is empty.
02438  */
02439 MD_Entry *MD_last_entry (MD_Section *section)
02440 {
02441     MD_Symbol *symbol;
02442     
02443     symbol = section->entry_table->tail_symbol;
02444 
02445     if (symbol != NULL)
02446         return ((MD_Entry *) symbol->data);
02447     else
02448         return (NULL);
02449 }
02450 
02451 /* 
02452  * Returns a pointer to the next entry in the section or NULL if passed 
02453  * a pointer to the last entry in the section.
02454  */
02455 MD_Entry *MD_next_entry (MD_Entry *entry)
02456 {
02457     MD_Symbol *symbol;
02458 
02459     symbol = entry->symbol->next_symbol;
02460 
02461     if (symbol != NULL)
02462         return ((MD_Entry *) symbol->data);
02463     else
02464         return (NULL);
02465 }
02466 
02467 /* 
02468  * Returns a pointer to the previous entry in the section or NULL if passed 
02469  * a pointer to the first entry in the section.
02470  */
02471 MD_Entry *MD_prev_entry (MD_Entry *entry)
02472 {
02473     MD_Symbol *symbol;
02474 
02475     symbol = entry->symbol->prev_symbol;
02476 
02477     if (symbol != NULL)
02478         return ((MD_Entry *) symbol->data);
02479     else
02480         return (NULL);
02481 }
02482 
02483 /*
02484  * DO NOT CALL DIRECTLY! Use macro MD_set_entry_ext()! 
02485  * This is the function version of the macro MD_set_entry_ext().
02486  * 
02487  * Used to allow arguments to be checked for macro.
02488  */
02489 void *_MD_set_entry_ext(MD_Entry *entry, void *ext) 
02490 {
02491     entry->user_ext = ext;
02492 
02493     /* Return ext to be equivalent to macro version */
02494     return (ext);
02495 }
02496 
02497 /*
02498  * DO NOT CALL DIRECTLY! Use macro MD_get_entry_ext()!
02499  * This is the function version of the macro MD_get_entry_ext().
02500  * 
02501  * Used to allow arguments to be checked for macro.
02502  */
02503 void *_MD_get_entry_ext(MD_Entry *entry)
02504 {
02505     return (entry->user_ext);   
02506 }
02507  
02508 /* 
02509  * DO NOT CALL DIRECTLY!  Use macro MD_delete_entry()!
02510  * Frees the memory associated with a entry.
02511  * Used by MD_delete_entry macro and MD_delete_section.
02512  * 
02513  * Assumes entry has already been removed from the 
02514  * section's entry_table.
02515  */
02516 void _MD_free_entry (MD_Entry *entry)
02517 {
02518     char *name;
02519     int field_index, max_field_index;
02520     MD_Field **field_array, *field;
02521 
02522     /* Free name last (for error messages) */
02523     name = entry->name;
02524 
02525     /* Get the max_field_index and field array for ease of use */
02526     max_field_index = entry->section->max_field_index;
02527     field_array = entry->field;
02528 
02529     /* Free all the fields specified in field_array, 
02530      * Assumes max_field_index == -1 if field_array is NULL
02531      */
02532     for (field_index=0; field_index <= max_field_index; field_index++)
02533     {
02534         field = field_array[field_index];
02535         if (field != NULL)
02536             MD_delete_field (field);
02537     }
02538 
02539     /* Free the field array (if exists)*/
02540     if (field_array != NULL)
02541         free (field_array);
02542  
02543     /* Free the entry structure */
02544     L_free (MD_Entry_pool, entry);
02545 
02546     /* Free the entry's name */
02547     free (name);
02548 }
02549 
02550 /*
02551  * DO NOT CALL DIRECTLY! Use macro MD_delete_entry()!
02552  * This is the function version of the macro MD_delete_entry().
02553  * 
02554  * Used to allow arguments to be checked for macro.
02555  */
02556 void _MD_delete_entry (MD_Entry *entry)
02557 {
02558     /* Delete symbol and structure memory */
02559     MD_delete_symbol (entry->symbol, (void(*)(void *))_MD_free_entry);
02560 }
02561 
02562 /*
02563  * DO NOT CALL DIRECTLY!  Use macro MD_check_entry()!
02564  * This function checks the elements in the specified entry.
02565  * Used by the MD_check_entry() macro and _MD_check_section().
02566  * 
02567  * Returns the number of required fields not specified + the 
02568  * number of elements with incorrect type (0 if all ok).
02569  * 
02570  * If out is non-NULL, warning messages for non-specified required field
02571  * and for each element with incorrect type will be printed to out.
02572  *
02573  * The caller_name is used in the warning messages to identify the
02574  * routine/macro that started the checking process (MD_check_md, 
02575  * MD_check_section, or MD_check_entry).
02576  */
02577 int _MD_check_entry (FILE *out, MD_Entry *entry, char *caller_name)
02578 {
02579     MD_Section *section;
02580     MD_Field_Decl *field_decl, **field_decl_array;
02581     MD_Field *field;
02582     int max_field_index, field_index;
02583     int error_count;
02584 
02585     /* Initialize the error count */
02586     error_count = 0;
02587 
02588     /* Get the various pointers into local variables for ease of use */
02589     section = entry->section;
02590     field_decl_array = section->field_decl;
02591     max_field_index = section->max_field_index;
02592 
02593     /* Check all the fields in the array */
02594     for (field_index = 0; field_index <= max_field_index; field_index ++)
02595     {
02596         /* Get the field declaration for this field */
02597         field_decl = field_decl_array[field_index];
02598 
02599         /* If there is no field declared for this index, goto next index */
02600         if (field_decl == NULL)
02601             continue;
02602 
02603         /* Get the entry's field at this index */
02604         field = entry->field[field_index];
02605 
02606         /* Check the elements in the field if it exists */
02607         if (field != NULL)
02608         {
02609             /* Add in any error found by check_field */
02610             error_count += _MD_check_field (out, field, caller_name);
02611         }
02612         
02613         /* Otherwise warn if this field is required to be present */
02614         else if (field_decl->type == MD_REQUIRED_FIELD)
02615         {
02616             error_count++;
02617             if (out != NULL)
02618             {
02619                 MD_warn (out,
02620                          "%s(%s->%s->%s):\n  Warning, required field '%s' unspecified for entry '%s'.",
02621                          caller_name, section->name, entry->name, 
02622                          field_decl->name, field_decl->name, entry->name);
02623             }
02624         }
02625     }
02626 
02627     /* Return the number of errors detected */
02628     return (error_count);
02629 }
02630 
02631 /* Returns 1 if a legal identifier (C identifier), 0 otherwise */
02632 static int MD_legal_ident (char *ident)
02633 {
02634 
02635     char *ptr;
02636 
02637     /* Must start with letter of '_' (may not be empty string)*/
02638     if ((ident[0] != '_') && !isalpha (ident[0]))
02639         return (0);
02640 
02641     /* Rest of string must be alphnumeric or '_' */
02642     for (ptr = &ident[1]; *ptr != 0; ptr++)
02643     {
02644         if ((*ptr != '_') && !isalnum (*ptr))
02645             return (0);
02646     }
02647 
02648     /* Return legal */
02649     return (1);
02650 }
02651 
02652 /* Prints out a textual representation of the entry to out 
02653  * Called by MD_print_section().
02654  */
02655 void MD_print_entry (FILE *out, MD_Entry *entry, int page_width)
02656 {
02657     MD_Field **field_array, *field;
02658     MD_Field_Decl *field_decl;
02659     MD_Symbol *symbol;
02660     MD_Section *section;
02661     MD_Element **element_array, *element;
02662     char *entry_name, *field_name, *link_name;
02663     int effective_name_len, field_name_indent, first_field;
02664     int element_value_indent, value_len, print_column;
02665     int element_index, first_element;
02666     int max_assigned_index, link_valid_ident;
02667     char value_buf[500];
02668     int i;
02669 
02670     /* Set the indentation for the field names.
02671      * A setting of 17 allows names of length 14 on the same line
02672      * as first field.  Also puts openning '(' at 2 tabs in.
02673      */
02674     field_name_indent = 17;
02675     
02676     /* Get pointers for ease of use */
02677     entry_name = entry->name;
02678     field_array = entry->field;
02679     section = entry->section;
02680 
02681     /* Print out the entry name (with quotes if not a legal identifier) */
02682     if (!MD_legal_ident(entry_name))
02683     {
02684         fprintf (out, "  '%s'", entry_name);
02685         
02686         /* Calculate the effective entry name length 
02687          * (name_len + 2 for indent, 2 for quotes)
02688          */
02689         effective_name_len = strlen (entry_name) + 4;
02690     }
02691     else
02692     {
02693         fprintf (out, "  %s", entry_name);
02694 
02695         /* Calculate the effective entry name length 
02696          * (name_len + 2 for indent)
02697          */
02698         effective_name_len = strlen (entry_name) + 2;
02699     }
02700     
02701     /* Determine if can place first field on same line as entry name 
02702      * (Want to place a '(' after the entry name)
02703      */
02704     if ((effective_name_len + 1) > field_name_indent)
02705     {
02706         /* No, force newline and indent */
02707         putc ('\n', out);
02708 
02709         /* Indent, leaving space for '(' */
02710         for (i=1; i < field_name_indent; i++)
02711             putc (' ', out);
02712     }
02713     else
02714     {
02715         /* Yes, pad to place to place '(' */
02716         for (i=effective_name_len + 1; i < field_name_indent; i++)
02717             putc (' ', out);
02718     }
02719     
02720     /* Put the opening '(' */
02721     putc ('(', out);
02722 
02723     /* Mark that we are about to process the first field */
02724     first_field = 1;
02725 
02726     /* Print out fields in the order declared 
02727      * (verses the order they are in the field table)
02728      */
02729     for (symbol = section->field_decl_table->head_symbol; symbol != NULL;
02730          symbol = symbol->next_symbol)
02731     {
02732         /* Get the field declaration for this symbol */
02733         field_decl = (MD_Field_Decl *) symbol->data;
02734 
02735         /* Get the entry's field for this declaration */
02736         field = field_array[field_decl->field_index];
02737 
02738         /* If field has not been specified for this entry, goto next field */
02739         if (field == NULL)
02740             continue;
02741 
02742         /* Need to indent field name if this is not the first field */
02743         if (!first_field)
02744         {
02745             /* Goto next line */
02746             putc ('\n', out);
02747 
02748             /* Indent field name */
02749             for (i=0; i < field_name_indent; i++)
02750                 putc (' ', out);
02751         }
02752         /* Otherwise mark that next field will not be the first field */
02753         else
02754         {
02755             first_field = 0;
02756         }
02757         
02758         /* Get the field name for ease of use */
02759         field_name = field_decl->name;
02760 
02761         /* Get where all the element values should be indented (if needed) */
02762         element_value_indent = field_name_indent + strlen(field_name) + 1;
02763 
02764         /* Print the field's name and opening '('*/
02765         fprintf (out, "%s(", field_name);
02766 
02767         /* Set our print column to the current position */
02768         print_column = element_value_indent;
02769 
02770         /* Get the element array for ease of use */
02771         element_array = field->element;
02772 
02773         /* Make max_assigned_index point at the last element set to a value*/
02774         max_assigned_index = field->max_element_index;
02775         while ((max_assigned_index >= 0) &&
02776                (element_array[max_assigned_index] == NULL))
02777             max_assigned_index--;
02778         
02779         /* Mark that we are about to print the first element value 
02780          * on this line
02781          */
02782         first_element = 1;
02783 
02784         /* Print out all the element values for this field */
02785         for (element_index = 0; element_index <= max_assigned_index; 
02786              element_index ++)
02787         {
02788             /* Get the element for ease of use */
02789             element = element_array[element_index];
02790 
02791             /* Calculate the length of the value for this element.
02792              * Place the string for INT and DOUBLE in value_buf.
02793              */
02794             if (element == NULL)
02795                 value_len = 2;
02796             else
02797             {
02798                 switch (element->type)
02799                 {
02800                   case MD_INT:
02801                     /* Print int to buffer */
02802                     sprintf (value_buf, "%i", element->value.i);
02803                     value_len = strlen (value_buf);
02804                     break;
02805 
02806                   case MD_DOUBLE:
02807                     /* Print double to buffer with 10 trailing digits
02808                      * of precision and strip off trailing zeros 
02809                      * (min 1 trailing zero)
02810                      */
02811                     sprintf (value_buf, "%.10f", element->value.d);
02812                     value_len = strlen (value_buf);
02813                     while (value_len >= 2)
02814                     {
02815                         /* Stop at first non-zero value hit or
02816                          * at one zero before decimal
02817                          */
02818                         if ((value_buf[value_len-1] != '0') ||
02819                             (value_buf[value_len-2] == '.'))
02820                             break;
02821                         
02822                         /* Remove trailing zero */
02823                         value_len--;
02824                         value_buf[value_len] = 0;
02825                     }
02826                     break;
02827 
02828                   case MD_STRING:
02829                     /* Will need quotes around string */
02830                     value_len = strlen(element->value.s) + 2;
02831                     break;
02832 
02833                   case MD_LINK:
02834                     /* Quotes are needed around name if not valid ident */
02835                     link_name = element->value.l->name;
02836                     link_valid_ident = MD_legal_ident (link_name);
02837                     if (link_valid_ident)
02838                         value_len = strlen(link_name);
02839                     else
02840                         value_len = strlen(link_name) + 2;
02841                     break;
02842 
02843                   default:
02844                     MD_punt (entry->section->md,
02845                              "MD_print_entry: Unknown element type '%i'",
02846                              element->type);            
02847                 }
02848             }
02849             
02850             /*
02851              * If not first element, see if can fit on this line or if need
02852              * to goto the next line.  
02853              * (Always print first element on same line)
02854              */
02855             if (!first_element)
02856             {
02857                 /* See if we will exceed page width if this value is printed
02858                  * out, leaving 4 spaces for trailing ')); '
02859                  */
02860                 if ((print_column + value_len) >= (page_width - 4))
02861                 {
02862                     /* Goto next line */
02863                     putc ('\n', out);
02864 
02865                     /* Indent to element_value_indent */
02866                     for (i=0; i < element_value_indent; i++)
02867                         putc (' ', out);
02868 
02869                     /* Reset print_column */
02870                     print_column = element_value_indent;
02871                 }
02872 
02873                 /* Otherwise, just print space after last value */
02874                 else
02875                 {
02876                     putc (' ', out);
02877 
02878                     /* Update print_column */
02879                     print_column++;
02880                 }
02881             }
02882             /* Otherwise mark that next element will not be the first element
02883              * on this line
02884              */
02885             else
02886             {
02887                 first_element = 0;
02888             }
02889 
02890             /* Update print column */
02891             print_column += value_len;
02892 
02893 
02894             /* 
02895              * Print out the element's value.
02896              * INT, DOUBLE, and LINK use info from the value_len calculation.
02897              */
02898             if (element == NULL)
02899             {
02900                 fprintf (out, "()");
02901                 continue;
02902             }
02903 
02904             switch (element->type)
02905             {
02906                 /* For INT and DOUBLE, value placed in value buffer */
02907               case MD_INT:
02908               case MD_DOUBLE:
02909                 fprintf (out, "%s", value_buf);
02910                 break;
02911 
02912               case MD_STRING:
02913                 /* Print out string with '"' to identify it as a string */
02914                 fprintf (out, "\"%s\"", element->value.s);
02915                 break;
02916 
02917               case MD_LINK:
02918                 /* Print out name of entry linked to.  Put "'" around
02919                  * name if name not a valid identifier.
02920                  */
02921                 link_name = element->value.l->name;
02922                 if (link_valid_ident)
02923                     fprintf (out, "%s", link_name);
02924                 else
02925                     fprintf (out, "'%s'", link_name);
02926                 break;
02927 
02928               default:
02929                 MD_punt (entry->section->md,
02930                          "MD_print_entry: Unknown element type '%i'",
02931                          element->type);
02932             }
02933         }
02934         /* Closing out field */
02935         fprintf (out, ")");
02936     }
02937 
02938     /* Closing out entry */
02939     fprintf (out, ");\n");
02940 }
02941 
02942 /* Prints out a textual template for the entry (Entry name and (); only).
02943  *
02944  * Useful for listing the entries in a section/md.
02945  *
02946  * Called by MD_print_section_template().
02947  */
02948 void MD_print_entry_template (FILE *out, MD_Entry *entry)
02949 {
02950     char *entry_name;
02951     int effective_name_len, field_name_indent;
02952     int i;
02953 
02954     /* Set the indentation for the field names.
02955      * A setting of 17 allows names of length 14 on the same line
02956      * as first field.  Also puts openning '(' at 2 tabs in.
02957      */
02958     field_name_indent = 17;
02959     
02960     /* Get pointers for ease of use */
02961     entry_name = entry->name;
02962 
02963     /* Print out the entry name (with quotes if not a legal identifier) */
02964     if (!MD_legal_ident(entry_name))
02965     {
02966         fprintf (out, "  '%s'", entry_name);
02967         
02968         /* Calculate the effective entry name length 
02969          * (name_len + 2 for indent, 2 for quotes)
02970          */
02971         effective_name_len = strlen (entry_name) + 4;
02972     }
02973     else
02974     {
02975         fprintf (out, "  %s", entry_name);
02976 
02977         /* Calculate the effective entry name length 
02978          * (name_len + 2 for indent)
02979          */
02980         effective_name_len = strlen (entry_name) + 2;
02981     }
02982     
02983     /* Always (); on same line as entry name */
02984     /* Pad if necessary*/
02985     for (i=effective_name_len + 1; i < field_name_indent; i++)
02986         putc (' ', out);
02987 
02988     
02989     /* Put the opening and closing '();' */
02990     putc ('(', out);
02991     putc (')', out);
02992     putc (';', out);
02993     putc ('\n', out);
02994 }
02995 
02996 /* Creates a new field declaration in the specified section. */
02997 MD_Field_Decl *MD_new_field_decl (MD_Section *section, char *name, 
02998                                   MD_FIELD_TYPE field_type)
02999 {
03000     MD_Field_Decl *field_decl, **decl_array;
03001     int new_index, max_index;
03002 
03003     /* Allocate a new field declaration structure */
03004     field_decl = (MD_Field_Decl *) L_alloc (MD_Field_Decl_pool);
03005 
03006     /* Initialize the field declaration's fields */
03007     field_decl->section = section;
03008     field_decl->name = strdup (name);
03009     field_decl->type = field_type;
03010 
03011     field_decl->max_require_index = -1;
03012     field_decl->require = NULL;           /* Initially no requirements */
03013     field_decl->require_array_size = 0;
03014     field_decl->kleene_starred_req= NULL; /* Initially no starred requirement*/
03015 
03016     /* Search for next available field index in section */
03017     max_index = section->max_field_index;
03018     decl_array = section->field_decl;
03019     for (new_index=0; new_index <= max_index; new_index ++)
03020     {
03021         /* If slot in field_decl is empty, take it */
03022         if (decl_array[new_index] == NULL)
03023             break;
03024     }
03025 
03026     /* If new index exceeds current array size, resize field_decl array */
03027     if (new_index >= section->field_array_size)
03028         MD_resize_field_arrays (section, new_index);
03029 
03030     /* Place field declaration in new slot
03031      * Must use section->field_decl since the above resize call will change
03032      * the array!
03033      */
03034     section->field_decl[new_index] = field_decl;
03035     field_decl->field_index = new_index;
03036 
03037     /* Update max_field_index if necessary */
03038     if (section->max_field_index < new_index)
03039         section->max_field_index = new_index;
03040 
03041     /* Add to section's field declaration table, place pointer of added
03042      * symbol into section structure for easy access.
03043      */
03044     field_decl->symbol = MD_add_symbol (section->field_decl_table, 
03045                                         field_decl->name, (void *) field_decl);
03046 
03047     /* Return the new field declaration */
03048     return (field_decl);
03049 }
03050 
03051 /* Resizes the field_decl array in the section structure
03052  * and the field arrays in all the entries in the section.
03053  * 
03054  * Will allocate an array at least two bigger than what is needed for
03055  * max_index and will always round up to the next even number
03056  * (malloc has to align to a 8 byte boundary anyway, might as well
03057  *  use the memory).
03058  */
03059 static void MD_resize_field_arrays (MD_Section *section, int max_index)
03060 {
03061     MD_Field_Decl **new_decl_array, **old_decl_array;
03062     MD_Symbol *symbol;
03063     MD_Entry *entry;
03064     MD_Field **new_field_array, **old_field_array;
03065     int max_field_index, new_array_size, i;
03066 
03067     /* Increase size by first rounding up to the nearest odd number,
03068      * then adding 3 to it so that the new_array_size is always even
03069      * and has space for another 2 or 3 field declarations.
03070      */
03071     new_array_size = (max_index | 1) + 3;
03072 
03073     /* Sanity check */
03074     if (new_array_size <= section->field_array_size)
03075     {
03076         MD_punt (section->md,
03077                  "MD_resize_field_arrays: new_array_size (%i) must be > current size (%i)",
03078                  new_array_size, section->field_array_size);
03079     }
03080 
03081     /* Get the max_field_index for ease of use */
03082     max_field_index = section->max_field_index;
03083 
03084     /* 
03085      * Resize the field declaration array 
03086      */
03087 
03088     /* Create new field decl array */
03089     new_decl_array = (MD_Field_Decl **) malloc (sizeof (MD_Field_Decl *) * 
03090                                                 new_array_size);
03091     if (new_decl_array == NULL)
03092     {
03093         MD_punt (section->md, 
03094                  "MD_resize_field_arrays: Out of memory (size %i)",
03095                  new_array_size);
03096     }
03097 
03098     /* Get pointer to old array */
03099     old_decl_array = section->field_decl;
03100 
03101     /* Copy over pointers from existing array 
03102      * (Assumes max_field_index is -1 if old array is NULL).
03103      */
03104     for (i=0; i <= max_field_index; i++)
03105         new_decl_array[i] = old_decl_array[i];
03106 
03107     /* Initialize remaining pointers to NULL */
03108     for (i=max_field_index + 1; i < new_array_size; i++)
03109         new_decl_array[i] = NULL;
03110 
03111     /* Free old array, if not NULL */
03112     if (old_decl_array != NULL)
03113         free (old_decl_array);
03114     
03115     /* Install new field declaration array */
03116     section->field_decl = new_decl_array;
03117     section->field_array_size = new_array_size;
03118 
03119     /*
03120      * Resize all the field array in all the section's entries
03121      */
03122 
03123     /* Process each entry in the section */
03124     for (symbol = section->entry_table->head_symbol; symbol != NULL;
03125          symbol = symbol->next_symbol)
03126     {
03127         /* Get a pointer to this entry */
03128         entry = (MD_Entry *) symbol->data;
03129 
03130         /* Create new field array for this entry */
03131         new_field_array = (MD_Field **) malloc (sizeof (MD_Field *) * 
03132                                                 new_array_size);
03133         if (new_field_array == NULL)
03134         {
03135             MD_punt (section->md, 
03136                      "MD_resize_field_arrays: Out of memory (size %i)",
03137                      new_array_size);
03138         }
03139         
03140         /* Get pointer to old array for ease of use */
03141         old_field_array = entry->field;
03142         
03143         /* Copy over pointers from existing array 
03144          * (Assumes max_field_index is -1 if old array is NULL).
03145          */
03146         for (i=0; i <= max_field_index; i++)
03147             new_field_array[i] = old_field_array[i];
03148         
03149         /* Initialize remaining pointers to NULL */
03150         for (i=max_field_index + 1; i < new_array_size; i++)
03151             new_field_array[i] = NULL;
03152         
03153         /* Free old array, if not NULL */
03154         if (old_field_array != NULL)
03155             free (old_field_array);
03156         
03157         /* Install new field array into entry */
03158         entry->field = new_field_array;
03159     }
03160 }
03161 
03162 /*
03163  * DO NOT CALL DIRECTLY! Use macro MD_num_field_decls()!
03164  * This is the function version of the macro MD_num_field_decls().
03165  * 
03166  * Used to allow arguments to be checked for macros.
03167  */
03168 int _MD_num_field_decls (MD_Section *section)
03169 {
03170     /* Return number of declarations found in the section's field decl table */
03171     return (section->field_decl_table->symbol_count);
03172 }
03173 
03174 /*
03175  * DO NOT CALL DIRECTLY! Use macro MD_max_field_index()!
03176  * This is the function version of the macro MD_max_field_index().
03177  * 
03178  * Used to allow arguments to be checked for macros.
03179  */
03180 int _MD_max_field_index (MD_Section *section)
03181 {
03182     /* Return the index of the max declared field */
03183     return (section->max_field_index);
03184 }
03185 
03186 /*
03187  * DO NOT CALL DIRECTLY! Use macro MD_find_field_decl()!
03188  * This is the function version of the macro MD_find_field_decl().
03189  * 
03190  * Used to allow arguments to be checked for macros.
03191  */
03192 MD_Field_Decl *_MD_find_field_decl (MD_Section *section, char *name)
03193 {
03194     /* Find field_decl in section table, return data cast as MD_Field_Decl */
03195     return ((MD_Field_Decl *) _MD_find_symbol_data(section->field_decl_table,
03196                                               name));
03197 }
03198 
03199 /*
03200  * Returns a pointer to the first field declaration in the section or
03201  * NULL if no fields are declared for the section.
03202  */
03203 MD_Field_Decl *MD_first_field_decl (MD_Section *section)
03204 {
03205     MD_Symbol *symbol;
03206     
03207     symbol = section->field_decl_table->head_symbol;
03208 
03209     if (symbol != NULL)
03210         return ((MD_Field_Decl *) symbol->data);
03211     else
03212         return (NULL);
03213 }
03214 
03215 /*
03216  * Returns a pointer to the last field declaration in the section or
03217  * NULL if no fields are declared for the section.
03218  */
03219 MD_Field_Decl *MD_last_field_decl (MD_Section *section)
03220 {
03221     MD_Symbol *symbol;
03222     
03223     symbol = section->field_decl_table->tail_symbol;
03224 
03225     if (symbol != NULL)
03226         return ((MD_Field_Decl *) symbol->data);
03227     else
03228         return (NULL);
03229 }
03230 
03231 /* 
03232  * Returns a pointer to the next field declaration in the section or
03233  * NULL if passed a pointer to the last field declaration in the section
03234  */
03235 MD_Field_Decl *MD_next_field_decl (MD_Field_Decl *field_decl)
03236 {
03237     MD_Symbol *symbol;
03238 
03239     symbol = field_decl->symbol->next_symbol;
03240 
03241     if (symbol != NULL)
03242         return ((MD_Field_Decl *) symbol->data);
03243     else
03244         return (NULL);
03245 }
03246 
03247 /* 
03248  * Returns a pointer to the previous field declaration in the section or
03249  * NULL if passed a pointer to the first field declaration in the section
03250  */
03251 MD_Field_Decl *MD_prev_field_decl (MD_Field_Decl *field_decl)
03252 {
03253     MD_Symbol *symbol;
03254 
03255     symbol = field_decl->symbol->prev_symbol;
03256 
03257     if (symbol != NULL)
03258         return ((MD_Field_Decl *) symbol->data);
03259     else
03260         return (NULL);
03261 }
03262 
03263 
03264 
03265 /* 
03266  * DO NOT CALL DIRECTLY!  Use macro MD_delete_field_decl()!
03267  * Frees the memory associated with a field declaration.
03268  * Used by MD_delete_field_decl macro and MD_delete_section.
03269  * 
03270  * Assumes field declaration has already been removed from the 
03271  * section's field_decl_table.
03272  * 
03273  * Does not free this field's data in all the section's entries.
03274  * This is done externally by _MD_free_section() and MD_delete_field_decl().
03275  */
03276 void _MD_free_field_decl (MD_Field_Decl *field_decl)
03277 {
03278     char *name;
03279     MD_Element_Req **require, *element_req;
03280     int i, max_require_index;
03281     
03282     /* Free name last (for error messages) */
03283     name = field_decl->name;
03284 
03285     /* Remove field_decl from section's field_decl array */
03286     field_decl->section->field_decl[field_decl->field_index] = NULL;
03287 
03288     /* Get the require array and max index for ease of use */
03289     require = field_decl->require;
03290     max_require_index = field_decl->max_require_index;
03291 
03292     /* Delete element requirements in the require array
03293      * (Assumes max_require_index is -1 if require array is NULL) */
03294     for (i=0; i <= max_require_index; i++)
03295     {
03296         /* Get element to free */
03297         element_req = require[i];
03298 
03299         /* Free element_req description */
03300         free (element_req->desc);
03301 
03302         /* If a link, free link array */
03303         if (element_req->type == MD_LINK)
03304             free (element_req->link);
03305 
03306         /* Free element structure using L_free */
03307         L_free (MD_Element_Req_pool, element_req);
03308     }
03309 
03310     /* Free the require array (if exists) */
03311     if (require != NULL)
03312         free (require);
03313  
03314     /* Free the field declaration structure */
03315     L_free (MD_Field_Decl_pool, field_decl);
03316 
03317     /* Free the field_decl's name */
03318     free (name);
03319 }
03320 
03321 /* Deletes a field declaration and deletes all the data for this
03322  * field from all the entries in the section.
03323  */
03324 void MD_delete_field_decl (MD_Field_Decl *field_decl)
03325 {
03326     MD_Section *section;
03327     MD_Symbol *symbol;
03328     MD_Entry *entry;
03329     MD_Field *field;
03330     int field_index;
03331 
03332     /* Get the section for ease of use */
03333     section = field_decl->section;
03334     
03335     /* The the index of this field for ease of use */
03336     field_index = field_decl->field_index;
03337 
03338     /* Scan every entry in section and delete any info associated
03339      * with this name.  Must delete before freeing field decl
03340      * becuase MD_delete_field using field_decl info.
03341      */
03342     for (symbol = section->entry_table->head_symbol; symbol != NULL;
03343          symbol = symbol->next_symbol)
03344     {
03345         /* Get the entry for ease of use */
03346         entry = (MD_Entry *) symbol->data;
03347 
03348         /* Get the field pointer from the field array */
03349         field = entry->field[field_index];
03350 
03351         if (field != NULL)
03352         {
03353             MD_delete_field (field);
03354         }
03355     }
03356 
03357     /* Delete symbol and structure memory */
03358     MD_delete_symbol (field_decl->symbol, 
03359                       (void(*)(void *))_MD_free_field_decl);
03360 }
03361 
03362 /* Prints out a textual representation of a field declaration.
03363  * Called by MD_print_section().
03364  */
03365 void MD_print_field_decl (FILE *out, MD_Field_Decl *field_decl, int page_width)
03366 {
03367     MD_Element_Req **require_array, *require;
03368     MD_FIELD_TYPE type;
03369     char *field_name;
03370     int decl_len;
03371     int max_require_index, require_index, first_requirement;
03372     int require_indent,  print_column, i;
03373 
03374     /* Get various values into local variables for ease of use */
03375     type = field_decl->type;
03376     require_array = field_decl->require;
03377     max_require_index = field_decl->max_require_index;
03378     field_name = field_decl->name;
03379     
03380     /* Print out the type of field this is */
03381     if (type == MD_REQUIRED_FIELD)
03382     {
03383         fprintf (out, "  REQUIRED ");
03384     }
03385     else if (type == MD_OPTIONAL_FIELD)
03386     {
03387         fprintf (out, "  OPTIONAL ");
03388     }
03389     else
03390     {
03391         MD_punt (field_decl->section->md,
03392                  "MD_print_field_decl: Unknown field decl type '%i'",type);
03393     }
03394 
03395     /* Print out field name and openning '(' */
03396     fprintf (out, "%s(", field_name);
03397 
03398     /* Get the indentation to line up after openning '(' */
03399     require_indent = strlen (field_name) + 12;
03400 
03401     /* Get the current column position */
03402     print_column = require_indent;
03403     
03404     /* Mark that we are about to process the first requirement */
03405     first_requirement = 1;
03406 
03407     /* Print out the requirements for the field */
03408     for (require_index = 0; require_index <= max_require_index; 
03409          require_index++)
03410     {
03411         /* Get this requirment */
03412         require = require_array[require_index];
03413 
03414         /* Get the length of the requirement declaration */
03415         decl_len = strlen (require->desc);
03416 
03417         
03418         /* 
03419          * If not first requirement, see if can fit this requirement on
03420          * this line or if need to goto next line.
03421          * (Always print the first requirement on each line)
03422          */
03423         if (!first_requirement)
03424         {
03425             /* See if we will exceed page width if this decl is printed out,
03426              * leaving 3 spaces for trailing '); '
03427              */
03428             if ((print_column + decl_len) >= (page_width - 3))
03429             {
03430                 /* Goto next line */
03431                 putc ('\n', out);
03432 
03433                 /* Indent to line of with the declaration above */
03434                 for (i=0; i < require_indent; i++)
03435                     putc (' ', out);
03436 
03437                 /* Reset print_column */
03438                 print_column = require_indent;
03439             }
03440 
03441             /* Otherwise, just print space after last requirment */
03442             else
03443             {
03444                 putc (' ', out);
03445                 print_column ++;
03446             }
03447         }
03448 
03449         /* Otherwise, mark that the next requirement will not be first 
03450          * requirement on this line.
03451          */
03452         else
03453         {
03454             first_requirement = 0;
03455         }
03456 
03457         /* Update print_column */
03458         print_column += decl_len;
03459 
03460         /* Print out description of requirement */
03461         fprintf (out, "%s", require->desc);
03462     }
03463     
03464     /* Closing out field declaration */
03465     fprintf (out, ");\n");
03466 }
03467 
03468 /* Creates a new element requirement in the field declaration at
03469  * at the specified element index.
03470  * 
03471  * These element requirements must in order, starting from index 0.
03472  * For example, a requirment at index 1 cannot be created until
03473  * the requirement for index 0 is created.
03474  * 
03475  * These element requirements specify what type of data must go at
03476  * that index and that there must be data at that index.
03477  * These two properties are designed to reduce the error checking the 
03478  * md user must do.
03479  *
03480  * The name of the calling routine is passed in for error messages.
03481  * 
03482  * Returns a pointer to the new element_req structure 
03483  */
03484 static MD_Element_Req *MD_new_element_req (MD_Field_Decl *field_decl, 
03485                                            int index, char *caller_name)
03486 {
03487     MD_Element_Req *element_req, **old_require_array, **new_require_array;
03488     int i, new_array_size, max_require_index;
03489 
03490     /* Get max_require_index for ease of use */
03491     max_require_index = field_decl->max_require_index;
03492 
03493     /* Check that the index is valid, must be defining
03494      * the requirement just past the current requirements.
03495      */
03496     if (index != (max_require_index + 1))
03497     {
03498         /* Give error message for redefinition */
03499         if (index <= max_require_index)
03500         {
03501             MD_punt (field_decl->section->md,
03502                      "%s(%s->*->%s[%i]):\n  Element %i already required to be '%s'!",
03503                      caller_name, field_decl->section->name, field_decl->name, 
03504                      index, index, field_decl->require[index]->desc);
03505         }
03506         /* Otherwise, give error message for non-sequential definition */
03507         else
03508         {
03509             MD_punt (field_decl->section->md,
03510                      "%s(%s->*->%s[%i]):\n  Specify requirements for elements before %i first!",
03511                      caller_name, field_decl->section->name, field_decl->name, 
03512                      index, index);
03513         }
03514     }
03515     
03516     /* Check if trying to set a requirement past a kleene_starred
03517      * requirement.
03518      */
03519     if (field_decl->kleene_starred_req != NULL)
03520     {
03521         MD_punt (field_decl->section->md,
03522                  "%s(%s->*->%s[%i]):\n  Cannot specify requirements after a kleene starred requirement!",
03523                  caller_name, field_decl->section->name, field_decl->name, 
03524                  index);
03525     }
03526 
03527     /* Resize require array if necessary */
03528     if (index >= field_decl->require_array_size)
03529     {
03530         /* Increase size by first rounding up to the nearest odd number,
03531          * then adding 3 to it so that the new_require_array_size is always 
03532          * even and has space for another 2 or 3 requirements.
03533          */
03534         new_array_size = (index | 1) + 3;
03535 
03536         /* Allocate new array */
03537         new_require_array =(MD_Element_Req **)malloc(sizeof(MD_Element_Req *) *
03538                                                      new_array_size);
03539         if (new_require_array == NULL)
03540         {
03541             MD_punt (field_decl->section->md,
03542                      "Out of memory resizing require array (size %i).",
03543                      new_array_size);
03544         }
03545 
03546         /* Get old array ease of use */
03547         old_require_array = field_decl->require;
03548 
03549         /* Copy over pointers from existing array
03550          * (Assumes max_require_index is -1 if old array is NULL).
03551          */
03552         for (i=0; i <= max_require_index; i++)
03553             new_require_array[i] = old_require_array[i];
03554 
03555         /* Initialize remaining pointers to NULL */
03556         for (i=max_require_index + 1; i < new_array_size; i++)
03557             new_require_array[i] = NULL;
03558 
03559         /* Free old array, if not NULL */
03560         if (old_require_array != NULL)
03561             free (old_require_array);
03562 
03563         /* Install new require array */
03564         field_decl->require = new_require_array;
03565         field_decl->require_array_size = new_array_size;
03566     }
03567 
03568     /* Allocate element_req structure */
03569     element_req = (MD_Element_Req *) L_alloc (MD_Element_Req_pool);
03570 
03571     /* Initialize fields other than type and desc which should
03572      * always set by caller.
03573      */
03574     element_req->field_decl = field_decl;
03575     element_req->require_index = index;
03576     element_req->kleene_starred = 0; /* Initially not kleene_starred */
03577     element_req->link = NULL;
03578     element_req->link_array_size = 0;
03579 
03580     /* Place in require structure at correct index */
03581     field_decl->require[index] = element_req;
03582 
03583     /* Update max index (checking at top of function requires it to
03584      * be the new max)
03585      */
03586     field_decl->max_require_index = index;
03587 
03588     /* Return new structure */
03589     return (element_req);
03590 }
03591 
03592 /* Specifies that an int element is required at the index specified.
03593  * 
03594  * See description of MD_new_element_req() for restrictions on index
03595  * and the properties of element requirements.
03596  */
03597 void MD_require_int (MD_Field_Decl *field_decl, int element_index)
03598 {
03599     MD_Element_Req *element_req;
03600 
03601     /* Check element_index for validity, allocates element_req structure,
03602      * resize require array (if necessary) and places element_req in
03603      * the require array. 
03604      * All fields except type and desc initialized to correct values.
03605      *
03606      * Pass this function's name for error messages.
03607      */
03608     element_req = MD_new_element_req (field_decl, element_index, 
03609                                       "MD_require_int");
03610 
03611     /* Set element requirement to INT and set the description for error 
03612      * messages.
03613      */
03614     element_req->type = MD_INT;
03615     element_req->desc = strdup ("INT");
03616 }
03617 
03618 /* Specifies that an double element is required at the index specified.
03619  * 
03620  * See description of MD_new_element_req() for restrictions on index
03621  * and the properties of element requirements.
03622  */
03623 void MD_require_double (MD_Field_Decl *field_decl, int element_index)
03624 {
03625     MD_Element_Req *element_req;
03626 
03627     /* Check element_index for validity, allocates element_req structure,
03628      * resize require array (if necessary) and places element_req in
03629      * the require array. 
03630      * All fields except type and desc initialized to correct values.
03631      *
03632      * Pass this function's name for error messages.
03633      */
03634     element_req = MD_new_element_req (field_decl, element_index, 
03635                                       "MD_require_double");
03636 
03637     /* Set element requirement to INT and set the description for error 
03638      * messages.
03639      */
03640     element_req->type = MD_DOUBLE;
03641     element_req->desc = strdup ("DOUBLE");
03642 }
03643 
03644 /* Specifies that an string element is required at the index specified.
03645  * 
03646  * See description of MD_new_element_req() for restrictions on index
03647  * and the properties of element requirements.
03648  */
03649 void MD_require_string (MD_Field_Decl *field_decl, int element_index)
03650 {
03651     MD_Element_Req *element_req;
03652 
03653     /* Check element_index for validity, allocates element_req structure,
03654      * resize require array (if necessary) and places element_req in
03655      * the require array. 
03656      * All fields except type and desc initialized to correct values.
03657      *
03658      * Pass this function's name for error messages.
03659      */
03660     element_req = MD_new_element_req (field_decl, element_index, 
03661                                       "MD_require_string");
03662 
03663     /* Set element requirement to INT and set the description for error 
03664      * messages.
03665      */
03666     element_req->type = MD_STRING;
03667     element_req->desc = strdup ("STRING");
03668 }
03669 
03670 /* Specifies that a link (to a single target) element is required at the index
03671  * specified.  Use MD_require_multi_target_link() if multiple targets
03672  * are desired.
03673  * 
03674  * See description of MD_new_element_req() for restrictions on index
03675  * and the properties of element requirements.
03676  */
03677 void MD_require_link (MD_Field_Decl *field_decl, int element_index, 
03678                       MD_Section *section)
03679 {
03680     MD_Element_Req *element_req;
03681     MD_Section **link;
03682     int desc_length;
03683     char *desc;
03684     
03685 
03686     /* Check element_index for validity, allocates element_req structure,
03687      * resize require array (if necessary) and places element_req in
03688      * the require array. 
03689      * All fields except type and desc initialized to correct values.
03690      *
03691      * Pass this function's name for error messages.
03692      */
03693     element_req = MD_new_element_req (field_decl, element_index, 
03694                                       "MD_require_link");
03695 
03696 
03697     /* Allocate link array for section array */
03698     link = (MD_Section **)malloc (sizeof(MD_Section *));
03699     if (link == NULL)
03700     {
03701         MD_punt (field_decl->section->md,
03702                  "Out of memory allocating link array (size 1)");
03703     }
03704 
03705     /* Initialize link array */
03706     link[0] = section;
03707     
03708     /* Calculate the length of the description field */
03709     desc_length = strlen(section->name) + strlen("LINK()") + 1;
03710 
03711     /* Malloc description buffer */
03712     desc = (char *) malloc (sizeof(char) * desc_length);
03713     if (desc == NULL)
03714     {
03715         MD_punt (field_decl->section->md,
03716                  "Out of memory allocating link desc (size %i)",
03717                  desc_length);
03718     }
03719 
03720     /* Sanity check, mark where we expect terminator */
03721     desc[desc_length-1] = 1;
03722 
03723     /* Create description */
03724     sprintf (desc,"LINK(%s)", section->name);
03725 
03726     /* Sanity check, make sure terminator is where we expect it */
03727     if (desc[desc_length-1] != 0)
03728     {
03729         MD_punt (field_decl->section->md,
03730                  "link->desc incorrect length (%i)", desc_length);
03731     }
03732         
03733     /* Set element requirement to INT and set the description for error 
03734      * messages.
03735      */
03736     element_req->type = MD_LINK;
03737     element_req->desc = desc;
03738     element_req->link = link;
03739     element_req->link_array_size = 1;
03740 }
03741 
03742 /* Specifies that an multi-target link element is required at the index
03743  * specified.  
03744  * 
03745  * See description of MD_new_element_req() for restrictions on index
03746  * and the properties of element requirements.
03747  */
03748 void MD_require_multi_target_link (MD_Field_Decl *field_decl, 
03749                                    int element_index, int section_array_size,
03750                                    MD_Section **section_array)
03751 {
03752     MD_Element_Req *element_req;
03753     MD_Section **link, *section;
03754     int desc_length;
03755     char *desc, *desc_ptr, *name_ptr;
03756     int i;
03757     
03758 
03759     /* Check element_index for validity, allocates element_req structure,
03760      * resize require array (if necessary) and places element_req in
03761      * the require array. 
03762      * All fields except type and desc initialized to correct values.
03763      *
03764      * Pass this function's name for error messages.
03765      */
03766     element_req = MD_new_element_req (field_decl, element_index, 
03767                                       "MD_require_multi_target_link");
03768 
03769     /* Check array size passed */
03770     if (section_array_size <= 0)
03771     {
03772         MD_punt (field_decl->section->md,
03773                  "MD_require_multi_target_link: invalid array size (%i).",
03774                  section_array_size);
03775     }
03776 
03777     /* Allocate link array for section array */
03778     link = (MD_Section **)malloc (sizeof(MD_Section *) * section_array_size);
03779     if (link == NULL)
03780     {
03781         MD_punt (field_decl->section->md,
03782                  "Out of memory allocating link array (size %i)",
03783                  section_array_size);
03784     }
03785 
03786     /* Initialize link array */
03787     desc_length = 0;
03788     for (i=0; i < section_array_size; i++)
03789     {
03790         section = section_array[i];
03791         link[i] = section;
03792 
03793         /* Sum the length of all the section names */
03794         desc_length += strlen (section->name);
03795     }
03796 
03797     /* Add in the length of the wrapping string */
03798     desc_length += strlen ("LINK()");
03799 
03800     /* Add in the space for '|' and for terminator */
03801     desc_length += section_array_size;
03802 
03803     /* Malloc description buffer */
03804     desc = (char *) malloc (sizeof(char) * desc_length);
03805     if (desc == NULL)
03806         MD_punt (field_decl->section->md,
03807                  "Out of memory allocating link desc (size %i)",
03808                  desc_length);
03809 
03810     /* Sanity check, mark where we expect terminator */
03811     desc[desc_length-1] = 1;
03812 
03813     /* Create description */
03814     strcpy (desc, "LINK(");
03815     desc_ptr = &desc[5];
03816 
03817     for (i=0; i < section_array_size; i++)
03818     {
03819         /* Copy name to description */
03820         for (name_ptr = link[i]->name; *name_ptr != 0; name_ptr++)
03821         {
03822             *desc_ptr = *name_ptr;
03823             desc_ptr++;
03824         }
03825         /* Add '|' between names */
03826         if ((i+1) < section_array_size)
03827         {
03828             *desc_ptr = '|';
03829             desc_ptr++;
03830         }
03831     }
03832     
03833     /* Add ending ')' and terminator */
03834     *desc_ptr = ')';
03835     desc_ptr++;
03836     *desc_ptr = 0;
03837 
03838     /* Sanity check, make sure terminator is where we expect it */
03839     if (desc[desc_length-1] != 0)
03840     {
03841         MD_punt (field_decl->section->md,
03842                  "link->desc incorrect length (%i)", desc_length);
03843     }
03844         
03845     /* Set element requirement to INT and set the description for error 
03846      * messages.
03847      */
03848     element_req->type = MD_LINK;
03849     element_req->desc = desc;
03850     element_req->link = link;
03851     element_req->link_array_size = section_array_size;
03852 }
03853 
03854 
03855 /* Specifies that the requirement at the index speicifed should be treated
03856  * as a kleene starred requirement (0 or more required).
03857  *
03858  * Only the last requirement may be kleene starred.
03859  */
03860 void MD_kleene_star_requirement (MD_Field_Decl *field_decl, int element_index)
03861 {
03862     MD_Element_Req *element_req;
03863     char *new_desc;
03864     int max_require_index;
03865 
03866     max_require_index = field_decl->max_require_index;
03867 
03868     /* Make sure that the element index is in range */
03869     if ((element_index < 0) || (element_index > max_require_index))
03870     {
03871         MD_punt (field_decl->section->md,
03872                  "MD_kleene_star_requirement(%s->*->%s[%i]:\n  Invalid element index %i (the max valid index is %i).",
03873                  field_decl->section->name, field_decl->name,
03874                  element_index, element_index, max_require_index);
03875     }
03876 
03877     /* Must be specifying the last requirement */
03878     if (element_index != max_require_index)
03879     {
03880         MD_punt (field_decl->section->md,
03881                  "MD_kleene_star_requirement(%s->*->%s[%i]:\n  Only the last requirment (%i) may be kleene starred.",
03882                  field_decl->section->name, field_decl->name,
03883                  element_index, max_require_index);
03884     }
03885     
03886     /* Get the requirement that we want to kleene star */
03887     element_req = field_decl->require[element_index];
03888 
03889     /* Prevent from being called twice (to aid debugging) */
03890     if (element_req->kleene_starred)
03891     {
03892         MD_punt (field_decl->section->md,
03893                  "MD_kleene_star_requirement(%s->*->%s[%i]:\n  Requirement already kleene starred.",
03894                  field_decl->section->name, field_decl->name,
03895                  element_index);
03896         
03897     }
03898     
03899     /* Sanity check, something else better not be marked kleene_starred */
03900     if (field_decl->kleene_starred_req != NULL)
03901     {
03902         MD_punt (field_decl->section->md,
03903                  "MD_kleene_star_requirement(%s->*->%s[%i]:\n  Algorithm error, %i marked kleene starred... why?.",
03904                  field_decl->section->name, field_decl->name,
03905                  element_index, field_decl->kleene_starred_req->require_index);
03906     }
03907 
03908     /* Mark element as kleene starred and point field decl at it */
03909     element_req->kleene_starred = 1;
03910     field_decl->kleene_starred_req = element_req;
03911 
03912     /* Change requirement description to have extra star added */
03913     new_desc = MD_concat_strings (element_req->desc, "*");
03914 
03915     /* Free old desc */
03916     free (element_req->desc);
03917 
03918     /* Point to new description */
03919     element_req->desc = new_desc;
03920 }
03921 
03922 /* Creates a new field for the entry of type decl with an initial
03923  * size suitable for the specified number of elements.  The field
03924  * automatically resizes (upward) when appropriate, so 0 elements
03925  * may be specified.
03926  */
03927 MD_Field *MD_new_field (MD_Entry *entry, MD_Field_Decl *decl, 
03928                                int num_elements)
03929 {
03930     MD_Field *field, **field_slot;
03931 
03932     /* Sanity check, make sure everything is initialized properly */
03933     if (MD_Field_pool == NULL)
03934     {
03935         MD_punt (NULL, 
03936                  "MD routines not initialized (call MD_new_md() first)!");
03937     }
03938     field = (MD_Field *) L_alloc (MD_Field_pool);
03939 
03940     /* Initialize fields */
03941     field->entry = entry;
03942     field->decl = decl;
03943     field->max_element_index = -1;      /* No elements specified */
03944 
03945     /* Get place in entry's field array to place field */
03946     field_slot = &entry->field[decl->field_index];
03947     
03948     /* Make sure this field has not already been created for this entry */
03949     if (*field_slot != NULL)
03950     {
03951         MD_punt (entry->section->md,
03952                  "%s, entry %s: Cannot create field '%s', already exists!", 
03953                  entry->section->name, entry->name, decl->name);
03954     }
03955 
03956     /* Place in field in the proper slot in the entry's field array */
03957     *field_slot = field;
03958 
03959     /* Punt if invalid num_elements passed */
03960     if (num_elements < 0)
03961     {
03962         MD_punt (entry->section->md,
03963                  "%s, entry %s, creating field %i: num_elements (%i) must be >= 0",
03964                  entry->section->name, entry->name, decl->name, num_elements);
03965     }
03966 
03967     /* Initialize to no array allocated */
03968     field->element = NULL;
03969     field->element_array_size = 0;
03970 
03971     /* Create array of specified size, unless 0 */
03972     if (num_elements > 0)
03973     {
03974         MD_resize_element_array (field, num_elements - 1);
03975     }
03976 
03977     return (field);
03978 }
03979 
03980 /* Increases the size of a field's element array . */
03981 static void MD_resize_element_array (MD_Field *field, int max_index)
03982 {
03983     MD_Element **old_array, **new_array;
03984     int new_size;
03985     int i;
03986     
03987     /* Increase size so that it is increased to an even multiple of four.
03988      * Helps reduce overhead of adding multiple elements.
03989      * Max element is 0 based, so need to add one to size anyways!
03990      */
03991     new_size = (max_index | 3) + 1;
03992 
03993     /* Sanity check */
03994     if (new_size <= field->element_array_size)
03995     {
03996         MD_punt (field->entry->section->md,
03997                  "MD_resize_element_array: new_size (%i) must be > current size (%i)",
03998                  new_size, field->element_array_size);
03999     }
04000 
04001     /* Create new element array */
04002     new_array = (MD_Element **) malloc (sizeof(MD_Element *) * new_size);
04003     if (new_array == NULL)
04004     {
04005         MD_punt (field->entry->section->md, 
04006                  "MD_resize_element_array: Out of memory");
04007     }
04008 
04009     /* Get pointer to old array */
04010     old_array = field->element;
04011 
04012     /* Copy over pointers from existing array 
04013      * (Assumes max_element_index is -1 if old array is NULL).
04014      */
04015     for (i=field->max_element_index; i >= 0; i--)
04016         new_array[i] = old_array[i];
04017 
04018     /* Initialize remaining pointers to NULL */
04019     for (i=field->max_element_index + 1; i < new_size; i++)
04020         new_array[i] = NULL;
04021 
04022     /* Free old array, if not NULL */
04023     if (old_array != NULL)
04024         free (old_array);
04025 
04026     /* Install new array */
04027     field->element = new_array;
04028     field->element_array_size = new_size;
04029 }
04030 
04031 /* DO NOT CALL DIRECTLY! Use macro MD_find_field()!
04032  * This is the function version of MD_find_field()
04033  * 
04034  * Does a little more error check than the macro.
04035  */
04036 MD_Field *_MD_find_field (MD_Entry *entry, MD_Field_Decl *field_decl)
04037 {
04038     MD_Field *field;
04039 
04040     /* Make sure the entry and field_decl are for the same section */
04041     if (entry->section != field_decl->section)
04042     {
04043         MD_punt (entry->section->md,
04044                  "MD_find_field: entry (%s) from section %s and field decl (%s) from %s!",
04045                  entry->name, entry->section->name, field_decl->name,
04046                  field_decl->section->name);
04047     }
04048 
04049     /* Get the field from the entry (may be NULL) */
04050     field = entry->field[field_decl->field_index];
04051 
04052     return (field);
04053 }
04054 
04055 /* Delete a field from an entry */
04056 void MD_delete_field (MD_Field *field)
04057 {
04058     MD_Element *element, **element_array;
04059     int index, max_element_index;
04060 
04061     /* Get max_element_index and the element array for ease of use */
04062     max_element_index = field->max_element_index;
04063     element_array = field->element;
04064 
04065     /* Free all the element's allocated. 
04066      * (Assumes max_element_index == -1 if element_array is NULL
04067      */
04068     for (index = 0; index <= max_element_index; index++)
04069     {
04070         /* Get the element (may be NULL) */
04071         element = element_array[index];
04072 
04073         /* Free element if non-NULL */
04074         if (element != NULL)
04075         {
04076             /* If element is a string, free string */
04077             if (element->type == MD_STRING)
04078                 free (element->value.s);
04079 
04080             L_free (MD_Element_pool, element);
04081         }
04082     }
04083     
04084     /* Free element array (if exists)*/
04085     if (element_array != NULL)
04086         free (element_array);
04087 
04088     /* Remove field pointer from entry field array */
04089     field->entry->field[field->decl->field_index] = NULL;
04090 
04091     /* Free field structure */
04092     L_free (MD_Field_pool, field);
04093 }
04094 
04095 /*
04096  * DO NOT CALL DIRECTLY!  Use macro MD_check_field()!
04097  * This function checks the elements in the specified field.
04098  * Used by the MD_check_field() macro and _MD_check_entry().
04099  * 
04100  * Returns the number of elements with incorrect type (0 if all ok).
04101  * 
04102  * If out is non-NULL, warning messages for each incorrect type will
04103  * be printed to out.
04104  *
04105  * The caller_name is used in the warning messages to identify the
04106  * routine/macro that started the checking process (MD_check_md, 
04107  * MD_check_section, MD_check_entry, or MD_check_field).
04108  */
04109 int _MD_check_field (FILE *out, MD_Field *field, char *caller_name)
04110 {
04111     MD_Field_Decl *field_decl;
04112     MD_Element_Req **require_array, *requirement, *kleene_starred_req;
04113     MD_Element **element_array, *element;
04114     MD_Section *section, **link_array, *target_section;
04115     MD_Entry *entry;
04116     int max_element_index, max_require_index;
04117     int max_non_kleene_index, max_assigned_index, max_check_index;
04118     int link_array_size, valid_link;
04119     int i, j;
04120     int error_count;
04121     
04122     /* Initialize the error count */
04123     error_count = 0;
04124 
04125     /* Get the various pointers into local variables for ease of use */
04126     field_decl = field->decl;
04127     element_array = field->element;
04128     max_element_index = field->max_element_index;
04129     require_array = field_decl->require;
04130     max_require_index = field_decl->max_require_index;
04131     kleene_starred_req = field_decl->kleene_starred_req;
04132     entry = field->entry;
04133     section = entry->section;
04134 
04135     /* Make max_assigned_index point at the last element set to a value*/
04136     max_assigned_index = max_element_index;
04137     while ((max_assigned_index >= 0) && 
04138            (element_array[max_assigned_index] == NULL))
04139         max_assigned_index--;
04140 
04141     /* Get the index of the last non-kleene starred requirement */
04142     if (kleene_starred_req != NULL)
04143         max_non_kleene_index = max_require_index -1;
04144     else
04145         max_non_kleene_index = max_require_index;
04146 
04147     /* Get the last index we need to check 
04148      * (check to maximum non-kleene starred requirement or to last
04149      * assigned index.)
04150      */
04151     if (max_assigned_index > max_non_kleene_index)
04152         max_check_index = max_assigned_index;
04153     else
04154         max_check_index = max_non_kleene_index;
04155      
04156 
04157     /* Scan all the elements that require checking.*/
04158     for (i=0; (i <= max_check_index); i++)
04159     {
04160         if (i <= max_assigned_index)
04161             element = element_array[i];
04162         else
04163             element = NULL;
04164 
04165         if (i <= max_non_kleene_index)
04166             requirement = require_array[i];
04167         else
04168             requirement = kleene_starred_req;
04169 
04170         /* Don't print out error message if both element and requirement
04171          * are NULL.
04172          */
04173         if ((element == NULL) && (requirement == NULL))
04174             continue;
04175         
04176         /* Handle NULL elements */
04177         if (element == NULL)
04178         {
04179             error_count++;
04180             if (out != NULL)
04181             {
04182                 MD_warn (out,
04183                          "%s(%s->%s->%s[%i]):\n  Warning, %s required not NULL.",
04184                          caller_name, section->name, entry->name, 
04185                          field_decl->name, i, requirement->desc);
04186             }
04187         }
04188 
04189         /* Handle NULL requirement */
04190         else if (requirement == NULL)
04191         {
04192             error_count++;
04193             if (out != NULL)
04194             {
04195                 MD_warn (out,
04196                          "%s(%s->%s->%s[%i]):\n  Warning, NULL required not %s.",
04197                          caller_name, section->name, entry->name, 
04198                          field_decl->name, i, MD_type_name[element->type]);
04199             }
04200         }
04201 
04202         else if (element->type != requirement->type)
04203         {
04204             error_count++;
04205             if (out != NULL)
04206             {
04207                 MD_warn (out,
04208                          "%s(%s->%s->%s[%i]):\n  Warning, %s required not %s.",
04209                          caller_name, section->name, entry->name, 
04210                          field_decl->name, i, requirement->desc, 
04211                          MD_type_name[element->type]);
04212             }
04213         }
04214         else if (element->type == MD_LINK)
04215         {
04216             link_array = requirement->link;
04217             link_array_size = requirement->link_array_size;
04218             target_section = element->value.l->section;
04219             valid_link = 0;
04220             
04221             for (j=0; j < link_array_size; j++)
04222             {
04223                 if (link_array[j] == target_section)
04224                 {
04225                     valid_link = 1;
04226                     break;
04227                 }
04228             }
04229 
04230             if (!valid_link)
04231             {
04232                 error_count++;
04233                 if (out != NULL)
04234                 {
04235                     MD_warn (out,
04236                            "%s(%s->%s->%s[%i]):\n  Warning, %s required not link to %s->%s.",
04237                              caller_name, section->name, entry->name, 
04238                              field_decl->name, i, requirement->desc, 
04239                              target_section->name, element->value.l->name);
04240                 }
04241             }
04242         }
04243     }
04244 
04245     /* Return count of error encountered */
04246     return (error_count);
04247 }
04248 
04249 
04250 /* Used by the MD_set_xxx routines to do type checking */
04251 static int MD_check_setting (FILE *out, MD_Field *field, int index, char *caller_name)
04252 {
04253     MD_Field_Decl *field_decl;
04254     MD_Element_Req *requirement;
04255     MD_Element *element;
04256     MD_Section **link_array, *target_section;
04257     int link_array_size, valid_link;
04258     int j;
04259 
04260     /* Get the various pointers into local variables for ease of use */
04261     field_decl = field->decl;
04262 
04263     if (index <= field->max_element_index)
04264         element = field->element[index];
04265     else
04266         element = NULL;
04267 
04268     if (index <= field_decl->max_require_index)
04269         requirement = field_decl->require[index];
04270     else
04271         requirement = field_decl->kleene_starred_req;
04272 
04273     /* Don't print out error message if both element and requirement
04274      * are NULL.
04275      */
04276     if ((element == NULL) && (requirement == NULL))
04277     {
04278         /* Return 0 to signal no errors found */
04279         return (0);
04280     }
04281         
04282     /* Handle NULL elements */
04283     if (element == NULL)
04284     {
04285         if (out != NULL)
04286         {
04287             MD_warn (out,
04288                      "%s(%s->%s->%s[%i]):\n  Warning, %s required not NULL.",
04289                      caller_name, field->entry->section->name, 
04290                      field->entry->name, field_decl->name, index, 
04291                      requirement->desc);
04292         }
04293         /* Return 1 to signal 1 error found */
04294         return (1);
04295     }
04296 
04297     /* Handle NULL requirement */
04298     else if (requirement == NULL)
04299     {
04300         if (out != NULL)
04301         {
04302             MD_warn (out,
04303                      "%s(%s->%s->%s[%i]):\n  Warning, NULL required not %s.",
04304                      caller_name, field->entry->section->name, 
04305                      field->entry->name, field_decl->name, index, 
04306                      MD_type_name[element->type]);
04307         }
04308         /* Return 1 to signal 1 error found */
04309         return (1);
04310     }
04311     else if (element->type != requirement->type)
04312     {
04313         if (out != NULL)
04314         {
04315             MD_warn (out,
04316                      "%s(%s->%s->%s[%i]):\n  Warning, %s required not %s.",
04317                      caller_name, field->entry->section->name, 
04318                      field->entry->name, field_decl->name, index, 
04319                      requirement->desc, MD_type_name[element->type]);
04320         }
04321         /* Return 1 to signal 1 error found */
04322         return (1);
04323     }
04324     else if (element->type == MD_LINK)
04325     {
04326         link_array = requirement->link;
04327         link_array_size = requirement->link_array_size;
04328         target_section = element->value.l->section;
04329         valid_link = 0;
04330             
04331         for (j=0; j < link_array_size; j++)
04332         {
04333             if (link_array[j] == target_section)
04334             {
04335                 valid_link = 1;
04336                 break;
04337             }
04338         }
04339         
04340         if (!valid_link)
04341         {
04342             if (out != NULL)
04343             {
04344                 MD_warn (out,
04345                         "%s(%s->%s->%s[%i]):\n  Warning, %s required not link to %s->%s.",
04346                          caller_name, field->entry->section->name, 
04347                          field->entry->name, field_decl->name, index, 
04348                          requirement->desc, target_section->name, 
04349                          element->value.l->name);
04350             }
04351             /* Return 1 to signal 1 error found */
04352             return (1);
04353         }
04354     }
04355 
04356     /* Return 0 to signal 0 errors found */
04357     return (0);
04358 }
04359 
04360 /*
04361  * DO NOT CALL DIRECTLY! Use macro MD_num_elements()!
04362  * This is the function version of the macro MD_num_elements().
04363  * 
04364  * Used to allow arguments to be checked for macros.
04365  */
04366 int _MD_num_elements (MD_Field *field)
04367 {
04368     /* Return number of elements in a field (DOES count NULL elements before
04369      * the last defined element).
04370      */
04371     return (field->max_element_index + 1);
04372 }
04373 
04374 /*
04375  * DO NOT CALL DIRECTLY! Use macro MD_max_element_index()!
04376  * This is the function version of the macro MD_max_element_index().
04377  * 
04378  * Used to allow arguments to be checked for macros.
04379  */
04380 int _MD_max_element_index (MD_Field *field)
04381 {
04382     /* Return the index of the last defined element in the field. */
04383     return (field->max_element_index);
04384 }
04385 
04386 
04387 /*
04388  * DO NOT CALL DIRECTLY!  Use macro MD_set_int()!
04389  * This is the function version of the macro MD_set_int() without
04390  * type checking.
04391  *
04392  * Sets the field element at index to the int value. 
04393  */
04394 void _MD_set_int (MD_Field *field, int index, int value)
04395 {
04396     MD_Element *element;
04397 
04398     /* Detect errors, make sure index is not negative! */
04399     if (index < 0)
04400     {
04401         MD_punt (field->entry->section->md,
04402                  "MD_set_int (%s->%s->%s[%d]): Invalid index (%d)\n",
04403                  field->entry->section->name, field->entry->name,
04404                  field->decl->name, index, index);
04405     }
04406 
04407     /* Detect need to increase max_element_index. */
04408     if (index > field->max_element_index)
04409     {
04410         /* Detect need to increase element array size */
04411         if (index >= field->element_array_size)
04412         {
04413             /* Increase element array size so index can be handled */
04414             MD_resize_element_array (field, index);
04415         }
04416 
04417         /* Set max_element_index to new value*/
04418         field->max_element_index = index;
04419     }
04420 
04421     /* Get element */
04422     element = field->element[index];
04423 
04424     /* Create element if doesn't exist */
04425     if (element == NULL)
04426     {
04427         element = (MD_Element *) L_alloc (MD_Element_pool);
04428         field->element[index] = element;
04429     }
04430 
04431     /* Otherwise, free string memory if the existing element is a string */
04432     else if (element->type == MD_STRING)
04433     {
04434         free (element->value.s);
04435     }
04436 
04437     /* Set content of element */
04438     element->field = field;
04439     element->element_index = (unsigned short) index;
04440     element->type = MD_INT;
04441     element->value.i = value;
04442 }
04443 
04444 /*
04445  * DO NOT CALL DIRECTLY!  Use macro MD_set_int()!
04446  * This is the function version of the macro MD_set_int() with
04447  * type checking.
04448  *
04449  * Sets the field element at index to the int value. 
04450  */
04451 void _MD_set_int_type_checking (MD_Field *field, int index, int value)
04452 {
04453     /* Call the normal set_int routine first */
04454     _MD_set_int (field, index, value);
04455 
04456     /* Call the check routine for this element */
04457     MD_check_setting (stderr, field, index, "MD_set_int");
04458 }
04459 
04460 /*
04461  * DO NOT CALL DIRECTLY!  Use macro MD_get_int()!
04462  * This is the function version of the macro MD_get_int().
04463  *
04464  * Gets the int value of the element at the specified index.
04465  * The user must prevent this routine from being called for a NULL element.
04466  * 
04467  * Unlike the macro, this verifies element type is correct.
04468  *
04469  */
04470 int _MD_get_int (MD_Field *field, int index)
04471 {
04472     MD_Element *element;
04473 
04474     /* Get the element */
04475     element = field->element[index];
04476 
04477     /* Make sure this is an int element */
04478     if (element->type != MD_INT)
04479     {
04480         MD_punt (field->entry->section->md, 
04481                  "MD_get_int(%s->%s->%s[%i]):\n  Accessing %s element as an INT!",
04482                  field->entry->section->name,
04483                  field->entry->name, field->decl->name,
04484                  index, MD_type_name[(int) element->type]);
04485     }
04486 
04487     /* Return element's value */
04488     return (element->value.i);
04489 }
04490 
04491 /*
04492  * DO NOT CALL DIRECTLY!  Use macro MD_set_double()!
04493  * This is the function version of the macro MD_set_double() without
04494  * type checking.
04495  *
04496  * Sets the field element at index to the double value 
04497  */
04498 void _MD_set_double (MD_Field *field, int index, double value)
04499 {
04500     MD_Element *element;
04501 
04502     /* Detect errors, make sure index is not negative! */
04503     if (index < 0)
04504     {
04505         MD_punt (field->entry->section->md,
04506                  "MD_set_double (%s->%s->%s[%d]): Invalid index (%d)\n",
04507                  field->entry->section->name, field->entry->name,
04508                  field->decl->name, index, index);
04509     }
04510 
04511     /* Detect need to increase max_element_index. */
04512     if (index > field->max_element_index)
04513     {
04514         /* Detect need to increase element array size */
04515         if (index >= field->element_array_size)
04516         {
04517             /* Increase element array size so index can be handled */
04518             MD_resize_element_array (field, index);
04519         }
04520 
04521         /* Set max_element_index to new value*/
04522         field->max_element_index = index;
04523     }
04524 
04525     /* Get element */
04526     element = field->element[index];
04527 
04528     /* Create element if doesn't exist */
04529     if (element == NULL)
04530     {
04531         element = (MD_Element *) L_alloc (MD_Element_pool);
04532         field->element[index] = element;
04533     }
04534     /* Otherwise, free string memory if the existing element is a string */
04535     else if (element->type == MD_STRING)
04536     {
04537         free (element->value.s);
04538     }
04539 
04540     /* Set content of element */
04541     element->field = field;
04542     element->element_index = (unsigned short) index;
04543     element->type = MD_DOUBLE;
04544     element->value.d = value;
04545 }
04546 
04547 /*
04548  * DO NOT CALL DIRECTLY!  Use macro MD_set_double()!
04549  * This is the function version of the macro MD_set_double() with
04550  * type checking.
04551  *
04552  * Sets the field element at index to the double value. 
04553  */
04554 void _MD_set_double_type_checking (MD_Field *field, int index, double value)
04555 {
04556     /* Call the normal set_double routine first */
04557     _MD_set_double (field, index, value);
04558 
04559     /* Call the check routine for this element */
04560     MD_check_setting (stderr, field, index, "MD_set_double");
04561 }
04562 
04563 /*
04564  * DO NOT CALL DIRECTLY!  Use macro MD_get_double()!
04565  * This is the function version of the macro MD_get_double().
04566  *
04567  * Gets the double value of the element at the specified index.
04568  * The user must prevent this routine from being called for a NULL element.
04569  * 
04570  * Unlike the macro, this verifies element type is correct.
04571  *
04572  */
04573 double _MD_get_double (MD_Field *field, int index)
04574 {
04575     MD_Element *element;
04576 
04577     /* Get the element */
04578     element = field->element[index];
04579 
04580     /* Make sure this is an double element */
04581     if (element->type != MD_DOUBLE)
04582     {
04583         MD_punt (field->entry->section->md, 
04584                  "MD_get_double(%s->%s->%s[%i]):\n  Accessing %s element as a DOUBLE!",
04585                  field->entry->section->name,
04586                  field->entry->name, field->decl->name,
04587                  index, MD_type_name[(int) element->type]);
04588     }
04589 
04590     /* Return element's value */
04591     return (element->value.d);
04592 }
04593 
04594 /*
04595  * DO NOT CALL DIRECTLY!  Use macro MD_set_string()!
04596  * This is the function version of the macro MD_set_string() without
04597  * type checking.
04598  * 
04599  * Sets the field element at index to the string value 
04600  */
04601 void _MD_set_string (MD_Field *field, int index, char *value)
04602 {
04603     MD_Element *element;
04604 
04605     /* Detect errors, make sure index is not negative! */
04606     if (index < 0)
04607     {
04608         MD_punt (field->entry->section->md,
04609                  "MD_set_string (%s->%s->%s[%d]): Invalid index (%d)\n",
04610                  field->entry->section->name, field->entry->name,
04611                  field->decl->name, index, index);
04612     }
04613 
04614     /* Detect need to increase max_element_index. */
04615     if (index > field->max_element_index)
04616     {
04617         /* Detect need to increase element array size */
04618         if (index >= field->element_array_size)
04619         {
04620             /* Increase element array size so index can be handled */
04621             MD_resize_element_array (field, index);
04622         }
04623 
04624         /* Set max_element_index to new value*/
04625         field->max_element_index = index;
04626     }
04627 
04628     /* Get element */
04629     element = field->element[index];
04630 
04631     /* Create element if doesn't exist */
04632     if (element == NULL)
04633     {
04634         element = (MD_Element *) L_alloc (MD_Element_pool);
04635         field->element[index] = element;
04636     }
04637     /* Otherwise, free string memory if the existing element is a string */
04638     else if (element->type == MD_STRING)
04639     {
04640         free (element->value.s);
04641     }
04642 
04643     /* Set content of element */
04644     element->field = field;
04645     element->element_index = (unsigned short) index;
04646     element->type = MD_STRING;
04647     element->value.s = strdup(value);
04648 }
04649 
04650 /*
04651  * DO NOT CALL DIRECTLY!  Use macro MD_set_string()!
04652  * This is the function version of the macro MD_set_string() with
04653  * type checking.
04654  *
04655  * Sets the field element at index to the string value. 
04656  */
04657 void _MD_set_string_type_checking (MD_Field *field, int index, char *value)
04658 {
04659     /* Call the normal set_string routine first */
04660     _MD_set_string (field, index, value);
04661 
04662     /* Call the check routine for this element */
04663     MD_check_setting (stderr, field, index, "MD_set_string");
04664 }
04665 
04666 /*
04667  * DO NOT CALL DIRECTLY!  Use macro MD_get_string()!
04668  * This is the function version of the macro MD_get_string().
04669  *
04670  * Gets the string value of the element at the specified index.
04671  * The user must prevent this routine from being called for a NULL element.
04672  * 
04673  * Unlike the macro, this verifies element type is correct.
04674  *
04675  */
04676 char *_MD_get_string (MD_Field *field, int index)
04677 {
04678     MD_Element *element;
04679 
04680     /* Get the element */
04681     element = field->element[index];
04682 
04683     /* Make sure this is an string element */
04684     if (element->type != MD_STRING)
04685     {
04686         MD_punt (field->entry->section->md, 
04687                  "MD_get_string(%s->%s->%s[%i]):\n  Accessing %s element as a STRING!",
04688                  field->entry->section->name,
04689                  field->entry->name, field->decl->name,
04690                  index, MD_type_name[(int) element->type]);
04691     }
04692 
04693     /* Return element's value */
04694     return (element->value.s);
04695 }
04696 
04697 /*
04698  * DO NOT CALL DIRECTLY!  Use macro MD_set_link()!
04699  * This is the function version of the macro MD_set_link() without
04700  * type checking.
04701  * 
04702  * Sets the field element at index to be a link to the specified entry.
04703  */
04704 void _MD_set_link (MD_Field *field, int index, MD_Entry *value)
04705 {
04706     MD_Element *element;
04707 
04708     /* Detect errors, make sure index is not negative! */
04709     if (index < 0)
04710     {
04711         MD_punt (field->entry->section->md,
04712                  "MD_set_link (%s->%s->%s[%d]):\n  Invalid index (%d)\n",
04713                  field->entry->section->name, field->entry->name,
04714                  field->decl->name, index, index);
04715     }
04716 
04717     /* Value may not be a NULL pointer */
04718     if (value == NULL)
04719     {
04720         MD_punt (field->entry->section->md,
04721                  "MD_set_link (%s->%s->%s[%d]):\n  Invalid value (pointer to NULL entry)\n",
04722                  field->entry->section->name, field->entry->name,
04723                  field->decl->name, index);
04724     }
04725 
04726     /* Detect need to increase max_element_index. */
04727     if (index > field->max_element_index)
04728     {
04729         /* Detect need to increase element array size */
04730         if (index >= field->element_array_size)
04731         {
04732             /* Increase element array size so index can be handled */
04733             MD_resize_element_array (field, index);
04734         }
04735 
04736         /* Set max_element_index to new value*/
04737         field->max_element_index = index;
04738     }
04739 
04740     /* Get element */
04741     element = field->element[index];
04742 
04743     /* Create element if doesn't exist */
04744     if (element == NULL)
04745     {
04746         element = (MD_Element *) L_alloc (MD_Element_pool);
04747         field->element[index] = element;
04748     }
04749     /* Otherwise, free string memory if the existing element is a string */
04750     else if (element->type == MD_STRING)
04751     {
04752         free (element->value.s);
04753     }
04754 
04755     /* Set content of element */
04756     element->field = field;
04757     element->element_index = (unsigned short) index;
04758     element->type = MD_LINK;
04759     element->value.l = value;
04760 }
04761 
04762 /*
04763  * DO NOT CALL DIRECTLY!  Use macro MD_set_link()!
04764  * This is the function version of the macro MD_set_link() with
04765  * type checking.
04766  *
04767  * Sets the field element at index to be a link to the specified entry.
04768  */
04769 void _MD_set_link_type_checking (MD_Field *field, int index, MD_Entry *value)
04770 {
04771     /* Call the normal set_link routine first */
04772     _MD_set_link (field, index, value);
04773 
04774     /* Call the check routine for this element */
04775     MD_check_setting (stderr, field, index, "MD_set_link");
04776 }
04777 
04778 /*
04779  * DO NOT CALL DIRECTLY!  Use macro MD_get_link()!
04780  * This is the function version of the macro MD_get_link().
04781  *
04782  * Gets the entry pointed to by the link element at the specified index.
04783  * The user must prevent this routine from being called for a NULL element.
04784  * 
04785  * Unlike the macro, this verifies element type is correct.
04786  *
04787  */
04788 MD_Entry *_MD_get_link (MD_Field *field, int index)
04789 {
04790     MD_Element *element;
04791 
04792     /* Get the element */
04793     element = field->element[index];
04794 
04795     /* Make sure this is an link element */
04796     if (element->type != MD_LINK)
04797     {
04798         MD_punt (field->entry->section->md, 
04799                  "MD_get_link(%s->%s->%s[%i]):\n  Accessing %s element as a LINK!",
04800                  field->entry->section->name,
04801                  field->entry->name, field->decl->name,
04802                  index, MD_type_name[(int) element->type]);
04803     }
04804 
04805     /* Return element's value */
04806     return (element->value.l);
04807 }
04808 
04809 /*
04810  * Deletes the field element at the index specified.
04811  */
04812 void MD_delete_element (MD_Field *field, int index)
04813 {
04814     MD_Element *element, **element_array;
04815     int max_index;
04816 
04817     /* Get the element array for ease of use */
04818     element_array = field->element;
04819 
04820     /* Get the element we are deleting */
04821     element = element_array[index];
04822     
04823     /* Do nothing if already NULL */
04824     if (element == NULL)
04825         return;
04826 
04827     /* Set the element at the index to NULL in the field's element array */
04828     element_array[index] = NULL;
04829 
04830     /* Free string if element is a string */
04831     if (element->type == MD_STRING)
04832     {
04833         free (element->value.s);
04834     }
04835 
04836     /* Free element */
04837     L_free (MD_Element_pool, element);
04838 
04839     /* Adjust the max_element_index for the field, may need to
04840      * scan over a range of NULL elements.  If field is now
04841      * empty, max_index should be set to -1
04842      */
04843     max_index = field->max_element_index;
04844     while ((max_index > -1) && (element_array[max_index] == NULL))
04845         max_index--;
04846     field->max_element_index = max_index;
04847 }
04848 
04849 
04850 #if 0
04851 /* Test out md routines */
04852 int main()
04853 {
04854     MD *md;
04855     MD_Section *section, *section2, *section_array[10];
04856     MD_Entry *entry;
04857     MD_Symbol_Table *table;
04858     MD_Symbol *symbol;
04859     MD_Field *field1, *field2;
04860     MD_Field_Decl *field_decl1, *field_decl2, *field_decl3, *field_decl4;
04861     MD_Field_Decl *decl[10];
04862     MD_Element *element;
04863     int i, found, j, error_count;
04864     char buf[100], *string;
04865     
04866 
04867     printf ("Testing md routines.\n");
04868 
04869     /* Create a new md */
04870     md = MD_new_md ("Test_md", 1);
04871 
04872     /* Create a new section */
04873     section = MD_new_section (md, "Test_section", 1, 0);
04874     printf ("%s max_field_index %i field_array_size %i\n",
04875             section->name, section->max_field_index,
04876             section->field_array_size);
04877 
04878     section2 = MD_new_section (md, "Section2", 0, 0);
04879 
04880     section_array[0] = section;
04881     section_array[1] = section2;
04882     
04883     /* Declare two fields */
04884     field_decl1 = MD_new_field_decl (section, "field1", MD_REQUIRED_FIELD);
04885     printf ("%s max_field_index %i field_array_size %i  %s index %i\n",
04886             section->name, section->max_field_index, section->field_array_size,
04887             field_decl1->name, field_decl1->field_index);
04888     field_decl2 = MD_new_field_decl (section, "field2", MD_REQUIRED_FIELD);
04889     printf ("%s max_field_index %i field_array_size %i  %s index %i\n",
04890             section->name, section->max_field_index, section->field_array_size,
04891             field_decl2->name, field_decl2->field_index);
04892 
04893     /* Require field1 to have exactly 1 int */
04894     MD_require_double (field_decl1, 0);
04895     MD_require_int (field_decl1, 1);
04896     MD_require_string (field_decl1, 2);
04897     MD_require_link (field_decl1, 3, section2);
04898     MD_require_multi_target_link (field_decl1, 4, 2, section_array);
04899     MD_require_double (field_decl1, 5);
04900     MD_require_int (field_decl1, 6);
04901     MD_require_string (field_decl1, 7);
04902     MD_require_link (field_decl1, 8, section2);
04903     MD_require_multi_target_link (field_decl1, 9, 2, section_array);
04904 
04905     MD_require_double (field_decl1, 10);
04906     MD_require_int (field_decl1, 11);
04907     MD_require_string (field_decl1, 12);
04908     MD_require_link (field_decl1, 13, section2);
04909     MD_require_multi_target_link (field_decl1, 14, 2, section_array);
04910     
04911     /* Test symbol table routines */
04912     table = section->entry_table;
04913     MD_print_symbol_table_hash (stdout, table);
04914 
04915     for (i=0; i < 10; i+= 3)
04916     {
04917         if (i == 3)
04918             sprintf (buf, "long_name_%i", i);
04919         else
04920             sprintf (buf, "d%i", i);
04921         entry = MD_new_entry (section, buf);
04922 
04923         /* Create some fields in each entry */
04924         field1 = MD_new_field (entry, field_decl1, 0);
04925         MD_set_double (field1, 0, ((double)i) * ((double) 1.001));
04926         MD_set_int (field1, 1, i); 
04927         sprintf (buf, "string%i", i);
04928         MD_set_string (field1, 2, buf);
04929         MD_set_link (field1, 4, entry);
04930 
04931         MD_set_double (field1, 5, (double)i);
04932         MD_set_int (field1, 6, i); 
04933         sprintf (buf, "string%i", i);
04934         MD_set_string (field1, 7, buf);
04935         MD_set_link (field1, 9, entry);
04936 
04937         MD_set_double (field1, 10, (double)i);
04938         MD_set_int (field1, 11, i); 
04939         sprintf (buf, "string%i", i);
04940         MD_set_string (field1, 12, buf);
04941         MD_set_link (field1, 14, entry);
04942 
04943         MD_get_int (field1, 1);
04944         field2 = MD_new_field (entry, field_decl2, 0);
04945         if (table->symbol_count == table->resize_size)
04946         {
04947             MD_print_symbol_table_hash (stdout, table);
04948         }
04949     }
04950 
04951     fprintf (stderr, "Sizeof MD_Element = %i\n", sizeof(MD_Element));
04952 
04953     field_decl3 = MD_new_field_decl (section, "field3", MD_REQUIRED_FIELD);
04954 
04955 /*
04956     fprintf (stderr, "\nBEGIN MD CHECK\n");
04957     error_count = MD_check_md (stderr, md);
04958     error_count = MD_check_section (stderr, section);
04959     
04960     entry = MD_find_entry(section, "d6");
04961     error_count = MD_check_entry (stderr, entry);
04962 
04963    field1 = MD_find_field (entry, field_decl1);
04964    error_count = MD_check_field (stderr, field1);
04965     fprintf (stderr, "END MD CHECK (%i errors found)\n\n", error_count);
04966 */
04967 
04968     MD_print_md (stdout, md, 80);
04969 /*
04970     MD_print_section (stdout, section, 80);
04971     entry = MD_find_entry(section, "d6");
04972     MD_print_entry (stdout, entry);
04973 */
04974     MD_print_symbol_table_hash (stdout, table);
04975     printf ("\n");
04976     printf ("%s max_field_index %i field_array_size %i  %s index %i\n",
04977             section->name, section->max_field_index, section->field_array_size,
04978             field_decl3->name, field_decl3->field_index);
04979     MD_delete_field_decl (field_decl2);
04980     field_decl4 = MD_new_field_decl (section, "field4", MD_OPTIONAL_FIELD);
04981     printf ("%s max_field_index %i field_array_size %i  %s index %i\n",
04982             section->name, section->max_field_index, section->field_array_size,
04983             field_decl4->name, field_decl4->field_index);
04984 
04985     for (j=5; j < 10; j++)
04986     {
04987         sprintf (buf, "field%i", j);
04988         decl[j] = MD_new_field_decl (section, buf, MD_OPTIONAL_FIELD);
04989         printf ("%s max_field_index %i field_array_size %i  %s index %i\n",
04990                 section->name, section->max_field_index, 
04991                 section->field_array_size, decl[j]->name, 
04992                 decl[j]->field_index);
04993         
04994     }
04995     found = 0;
04996     for (i=0; i < 1000; i+= 1)
04997     {
04998         sprintf (buf, "d%i", i);
04999         if ((entry = MD_find_entry (section, buf)) != NULL)
05000         {
05001             found ++;
05002             MD_delete_entry (entry); 
05003         }
05004         if (i == 500)
05005             MD_print_symbol_table_hash (stdout, table);
05006     }
05007     printf ("\n Found = %i\n", found);
05008 
05009 /*
05010     MD_resize_symbol_table(table);
05011 */
05012     MD_print_symbol_table_hash (stdout, table);
05013 
05014     section = MD_find_section(md, "Test_section");
05015     MD_delete_section(section);
05016 
05017     /* Delete the md */
05018     MD_delete_md (md);
05019     md = NULL;
05020 #if 0
05021     field = MD_new_field (NULL, NULL, 0);
05022     printf ("size %i max %i\n", field->array_size, field->max_element_index);
05023 
05024     for (i=0; i < 20; i ++)
05025     {
05026         MD_set_int (field, i, i);
05027         printf ("size %i max %i\n", field->array_size, 
05028                 field->max_element_index);
05029     }
05030     for (i=0; i < 20; i ++)
05031     {
05032         element = field->element[i];
05033         if (element != NULL)
05034         {
05035             printf ("%2i: %i type %i value\n", i, element->type, element->value.i);
05036         }
05037     }    
05038 
05039 #endif
05040     printf ("End md test.\n");
05041     return (0);
05042 }
05043 
05044 #endif

Generated on Mon Jul 21 20:28:01 2003 for TINKER LEGO DOC by doxygen 1.3.2