/* * Copyright (c) 2010 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Portions of this software have been released under the following terms: * * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION * * To anyone who acknowledges that this file is provided "AS IS" * without any express or implied warranty: * permission to use, copy, modify, and distribute this file for any * purpose is hereby granted without fee, provided that the above * copyright notices and this notice appears in all source code copies, * and that none of the names of Open Software Foundation, Inc., Hewlett- * Packard Company or Digital Equipment Corporation be used * in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. Neither Open Software * Foundation, Inc., Hewlett-Packard Company nor Digital * Equipment Corporation makes any representations about the suitability * of this software for any purpose. * * Copyright (c) 2007, Novell, Inc. All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Novell Inc. nor the names of its contributors * may be used to endorse or promote products derived from this * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @APPLE_LICENSE_HEADER_END@ */ /* ** ** NAME: ** ** NAMETBL.C ** ** FACILITY: ** ** Interface Definition Language (IDL) Compiler ** ** ABSTRACT: ** ** Name and scope table management ** ** VERSION: DCE 1.0 ** */ #include <stdint.h> #include <nidl.h> #include <ctype.h> #include <nidlmsg.h> #include <errors.h> #include <nametbl.h> #include <namtbpvt.h> /********************************************************************/ /* */ /* Private data declarations. */ /* */ /********************************************************************/ /* * Define the binding level stack. * * Bindings are associations between a name and an object. * The binding stack gets pushed each time a new naming scope is * entered, and popped when it is exited. * Each entry in the binding level stack points to the list of * bindings made at the current level. */ #define MAX_LEVELS 20 static NAMETABLE_binding_n_t * levelStack[MAX_LEVELS]; /* The level stack itself */ static int currentLevel; /* Current scoping level */ /* * The nametable root is allocated in static storage. Everything else is from * the heap. Also declare a cell to keep track of insertions since last * balancing. */ NAMETABLE_id_t NAMETABLE_root; static long NAMETABLE_unbalanced; /* * Definitions for the string table. This contains filenames, etc. */ #ifndef STRTAB_SIZE #define STRTAB_SIZE 10*1024 #endif /* * The head of the temporary name chain list and the temporary name flag. */ NAMETABLE_temp_name_t * NAMETABLE_temp_chain; static long NAMETABLE_names_are_temporary; /* Compiling for UNIX or AEGIS */ #define nameTable(id,member) (id)->member /******************************************************************************/ /* */ /* P R I V A T E I N T E R F A C E S */ /* */ /******************************************************************************/ /* * Function: Find the first set bit in a longword (4 byte longword). * * Inputs: A long, whose least-significant bit is to be found. * * Outputs: The position of the least significant bit. * * Functional Value: None * */ #define FIND_FIRST_SET find_first_set static void find_first_set ( uint32_t n_arg, uint32_t * position ) { long n, m, tp; tp = 31; n = n_arg; if ((m = n & 0X0000FFFF)) {tp = tp - 16; n = m;} if ((m = n & 0X00FF00FF)) {tp = tp - 8; n = m;} if ((m = n & 0X0F0F0F0F)) {tp = tp - 4; n = m;} if ((m = n & 0X33333333)) {tp = tp - 2; n = m;} if ((n & 0X55555555)) {tp = tp - 1;} *position = tp; } /* * Function: Balance the nametable tree. * * Inputs: None. (Implicitly, the root of the tree, NAMETABLE_root) * * Outputs: None. * * Functional Value: None * */ /* * The size of the array (balance_arr_size) must be the number of bits in * the variable n plus one. */ #define balance_arr_size 33 #define NAMETABLE_max_unbalance 10 static void NAMETABLE_balance_tree (void) { NAMETABLE_id_t This, temp = NULL, back, arr [balance_arr_size]; uint32_t i, n; /* * Initialize the array to NULL pointers. */ for (n=0; n<balance_arr_size; n++) { arr [n] = NULL; }; n = 0; /* * Initialize our node pointers. ("temp" is written before reading.) */ This = NAMETABLE_root; back = NULL; for (;;) { /* Termination of loop will be determined below */ /* * This works our way down to the bottom of the left most chain * of this subtree, the least valued member. */ for (; This != NULL;) { temp = This->left; /* Save the left pointer. */ This->left = back; /* Store the back pointer. */ if (back) /* Maintain the parent pointer */ back->parent = This; back = This; /* We now have a new back pointer. */ This = temp; /* And a new node to visit. */ }; /* for (; This != NULL;) */ /* * The loop above went one step too far. Back up one. * Also, if the result of backing up is NULL, we are done. */ if ((This = back) == NULL) break; back = This->left; /* Get a new back pointer */ ++n; /* Processing a new node. */ FIND_FIRST_SET (n, &i); /* Find the first set bit */ arr [i+1] = This; /* Save the current node */ This->left = temp = arr [i];/* New left pointer for this node */ if (temp) /* Maintain the parent pointer */ temp->parent = This; if ((temp = arr [i+2]) != NULL) { temp->right = This; /* Save this node as a right son. */ if (This) /* Maintain the parent pointer */ This->parent = temp; } /* * Done processing this node, clear out the descendants. */ for (; i>0; i--) arr [i] = NULL; /* * Set up for processing the next node. */ temp = This->right; This->right = NULL; This = temp; }; /* for (;;) */ /* * Done with phase 1. Handle the nametable root, then all the * remaining nodes are right sons. */ for (i = balance_arr_size -1; (i>0 && (temp = arr [i]) == 0); i--); NAMETABLE_root = temp; temp->parent = NULL; This = temp; for (i--; i>0; i--) { if ((temp = arr [i]) != 0) { This->right = temp; temp->parent = This; This = temp; } } /*for (i; i>0; i--)*/ /* * Now the tree is balanced. */ NAMETABLE_unbalanced = 0; } /* * Function: Delete a nametable node from the nametable. * * Inputs: node - the nametable node to be deleted. * * Outputs: None. * * Functional Value: None. * */ void NAMETABLE_delete_node ( NAMETABLE_id_t node ) { NAMETABLE_id_t n, /* The node being deleted */ p, /* The parent of the node being deleted */ l, /* The left child of the node being deleted */ r, /* The right child of the node being deleted */ t; /* Used to search for an insertion point in the tree */ /* * Get local copy of pointer to the node, and pointers to the * other nodes of interest. */ n = node; p = n->parent; l = n->left; r = n->right; /* * For this deletion algorithm, we are going to place "r" where "n" is now, * and then hang "l" off the end of "r"s left child chain. That's great, as * long as there is an "l" and and "r". If there is no "l", we simply * do the "r" operations and don't do the "l" operations. If there is neither * an "l" nor an "r", then performing the "r" operations has the correct * effect of nulling out "p"s appropriate chain. The problem comes when there * is an "l", but no "r"; this is because the "l" processing uses "r". * To handle this problem, we check for it and make "r" be "l", and null out * "l". */ if ((l != NULL) && (r == NULL)) { r = l; l = NULL; } /* * Handle the root of the tree specially. Make the right child the new root. */ if (p == NULL) { NAMETABLE_root = r; r->parent = NULL; } else { /* * Not deleting the root node. Determine if n is lc or rc of p. */ if (p->left == n) p->left = r; else if (p->right == n) p->right = r; else /* * Parent doesn't point to child. Corrupted nametable. */ INTERNAL_ERROR ("Corrupted name table"); /* * Make r's parent be p (if there is an r!). */ if (r != NULL) r->parent = p; } /* * Now r is hooked into the tree in the appropriate place. * We need to hang l next. Find the first null left pointer off of r * or r's left children. Hang l there. Of course, if l is NULL, we are done. */ if (l != NULL) { t = r; while (t->left != NULL) { t = t->left; } t->left = l; l->parent = t; } /* * At this point, node n has been removed from the tree, and the tree has * been reconnected. Now we need to free any associated binding, and then * free n itself. * * At the time this code is implemented, temporary names are only used * by the back end, and the back end does not associate bindings with them. * Therefore, simply bugcheck if there is a binding associated with this * nametable entry. */ if (n->bindings != NULL) INTERNAL_ERROR ("Binding associated with temporary name."); /* * Free the nametable node. This frees the id string storage as well, * since they were allocated as one chunk. */ FREE (n); } /* End of NAMETABLE_delete_node */ /******************************************************************************/ /* */ /* P U B L I C I N T E R F A C E S */ /* */ /******************************************************************************/ /* * Function: add an identifier to the id table. * * Inputs: id - The character string to be added. * * Outputs: * * Functional Value: a handle which can be used to refer to the * stored identifier. * */ NAMETABLE_id_t NAMETABLE_add_id ( const char * id ) { NAMETABLE_id_t This, parent = NULL, np, * insert_point = NULL; NAMETABLE_temp_name_t * new_temp_name_block; int i; char * cp; if (NAMETABLE_root == NULL) { /* The first entry in the name table. */ insert_point = &NAMETABLE_root; parent = NULL; } else { for (This = NAMETABLE_root; This; ) { if ((i = strcmp (id, This->id)) == 0) { /* We have a match. Return with This node id. */ return This; }; /* if strcmp */ /* No match, which subtree to use? */ if (i > 0) { /* * The id is greater than that of this node. * Use the right subtree. */ if (This->right == NULL) { insert_point = &This->right; parent = This; } This = This->right; } else { /* * The id is less than that of this node. * Use the left subtree. */ if (This->left == NULL) { insert_point = &This->left; parent = This; } This = This->left; }; /* if (i > 0) */ }; /* for */ }; /* NAMETABLE_root == NULL */ /* * At this point we have either returned with a match, or * have set up the pointer variable insert_point. * We need to allocate a new node and initialize it, hooking * it into the tree. */ This = MALLOC (sizeof (NAMETABLE_n_t) + strlen (id) + 1); /* Get a pointer to the buffer after the nametable node. */ np = This; cp = (char *) ++np; /* Copy the string into the buffer. */ strlcpy (cp, id, strlen (id) + 1); /* Initialize the nametable node. */ This -> left = NULL; This -> right = NULL; This -> id = cp; This -> bindings = NULL; This -> tagBinding = NULL; /* Link it into the nametable. */ assert(insert_point != NULL); *insert_point = This; This->parent = parent; /* If a temporary node, record it. */ if (NAMETABLE_names_are_temporary) { new_temp_name_block = NEW (NAMETABLE_temp_name_t); new_temp_name_block->next = NAMETABLE_temp_chain; new_temp_name_block->node = This; NAMETABLE_temp_chain = new_temp_name_block; } /* Indicate that we are getting unbalanced; balance tree if necessary*/ ++NAMETABLE_unbalanced; if (NAMETABLE_unbalanced > NAMETABLE_max_unbalance) NAMETABLE_balance_tree(); /* Return the id (the address of) the new node. */ return This; } /****************************************************************************/ /* * Function: Check if an identifier exists. * * Inputs: id - The character string to check for. * * Outputs: * * Functional Value: a handle which is used to refer to the * stored identifier. * */ NAMETABLE_id_t NAMETABLE_lookup_id ( const char * id ) { NAMETABLE_id_t This; int i; if (NULL == NAMETABLE_root) return NAMETABLE_NIL_ID; for (This = NAMETABLE_root; This; ) { if ((i = strcmp (id, This->id)) == 0) { /* We have a match. Return with this node id. */ return This; }; /* if strcmp */ /* No match, which subtree to use? */ if (i > 0) { /* id is greater than this node. Use right subtree. */ This = This->right; } else { /* id is less than this node. Use the left subtree. */ This = This->left; }; /* if (i > 0) */ }; /* for */ return NAMETABLE_NIL_ID; } /*--------------------------------------------------------------------*/ /* * Function: Converts an namtable identifier back to the original string. * * Inputs: id - The handle returned by NAMTABLE_add_id * * Outputs: str_ptr - The character string is returned through here. * * Functional Value: void * * Notes: * */ void NAMETABLE_id_to_string ( NAMETABLE_id_t NAMETABLE_id, const char ** str_ptr ) { NAMETABLE_id_t id; if (NAMETABLE_id == NAMETABLE_NIL_ID) *str_ptr = ""; else { id = NAMETABLE_id; *str_ptr = nameTable(id,id); }; } /*--------------------------------------------------------------------*/ /* * Function: Binds a symbol to a value. * * Inputs: id - The handle returned by NAMETABLE_add_id * * binding - a pointer representing the binding * * Outputs: * * Functional Value: Boolean true if binding completed successfully. * false if name already bound. * * Notes: For each symbol in the name table, there is a binding * stack. Conceptually the stack gets pushed every time * a new scope is entered, and popped on scope exit. The * symbol table is "shallowly bound" rather than * "deeply bound' in the lisp since. This makes lookup * fast, but pushing and popping slow. * */ boolean NAMETABLE_add_binding ( NAMETABLE_id_t id, const void * binding ) { NAMETABLE_id_t idP; NAMETABLE_binding_n_t * bindingP; NAMETABLE_binding_n_t * newBindingP; /* Get a local handle on the nametable entry. */ idP = id; if (!idP->bindings) { /* * First binding for this identifier. * */ /* Allocate and initialize the new binding. */ bindingP = NEW (NAMETABLE_binding_n_t); bindingP->oldBinding = NULL; } else { /* Get a handle on the binding chain. */ bindingP = idP->bindings; /* Fail if we already have a binding at this level. */ if (bindingP->bindingLevel == currentLevel) return false; /* Allocate and init this binding, making it the chain head. */ newBindingP = NEW (NAMETABLE_binding_n_t); newBindingP->oldBinding = bindingP; bindingP = newBindingP; }; /* Tie in the actual supplied binding. */ bindingP->theBinding = binding; /* Mark the level, tie it into the level chain. */ bindingP->bindingLevel = currentLevel; bindingP->nextBindingThisLevel = levelStack[currentLevel]; levelStack[currentLevel] = bindingP; /* Create the back link to the name table and hook it into the id. */ bindingP->boundBy = idP; idP->bindings = bindingP; return true; } /*--------------------------------------------------------------------*/ /* * Function: Returns the binding associated with the id * * Inputs: id - The handle returned by NAMETABLE_add_id * * * Outputs: * * Functional Value: - A pointer to the binding if there is one, * 0 otherwise. * */ const void *NAMETABLE_lookup_binding ( NAMETABLE_id_t identifier ) { if (identifier == NAMETABLE_NIL_ID) return NULL; if (nameTable(identifier,bindings) == NULL) { return NULL; }; return nameTable(identifier,bindings)->theBinding; } /*--------------------------------------------------------------------*/ /* * Function: Binds a tag symbol to a value. * * Inputs: id - The handle returned by NAMETABLE_add_id * * binding - a pointer representing the binding * * Outputs: * * Functional Value: Boolean true if binding completed successfully. * false if name already bound. * * Notes: For each symbol in the name table, there is a binding * stack. Conceptually the stack gets pushed every time * a new scope is entered, and popped on scope exit. The * symbol table is "shallowly bound" rather than * "deeply bound' in the lisp since. This makes lookup * fast, but pushing and popping slow. * */ boolean NAMETABLE_add_tag_binding ( NAMETABLE_id_t id, const void * binding ) { NAMETABLE_id_t idP; NAMETABLE_binding_n_t * bindingP; NAMETABLE_binding_n_t * newBindingP; /* Get a local handle on the nametable entry. */ idP = id; if (!idP->tagBinding) { /* * First binding for this identifier. * */ /* Allocate and initialize the new binding. */ bindingP = NEW (NAMETABLE_binding_n_t); bindingP->oldBinding = NULL; } else { /* Get a handle on the binding chain. */ bindingP = idP->tagBinding; /* Fail if we already have a binding at this level. */ if (bindingP->bindingLevel == currentLevel) return false; /* Allocate and init this binding, making it the chain head. */ newBindingP = NEW (NAMETABLE_binding_n_t); newBindingP->oldBinding = bindingP; bindingP = newBindingP; }; /* Tie in the actual supplied binding. */ bindingP->theBinding = binding; /* Create the back link to the name table and hook it into the id. */ bindingP->boundBy = idP; idP->tagBinding = bindingP; return true; } /*--------------------------------------------------------------------*/ /* * Function: Returns the binding associated with the tag id * * Inputs: id - The handle returned by NAMETABLE_add_id * * * Outputs: * * Functional Value: - A pointer to the binding if there is one, * 0 otherwise. * */ const void *NAMETABLE_lookup_tag_binding ( NAMETABLE_id_t identifier ) { if (identifier == NAMETABLE_NIL_ID) return NULL; if (nameTable(identifier,tagBinding) == NULL) { return NULL; }; return nameTable(identifier,tagBinding)->theBinding; } /*--------------------------------------------------------------------*/ /* * Function: Returns the binding associated with the id. The binding must * be within the local scope. * * Inputs: id - The handle returned by NAMETABLE_add_id * * * Outputs: * * Functional Value: - A pointer to the binding if there is one, * 0 otherwise. * */ const void *NAMETABLE_lookup_local ( NAMETABLE_id_t identifier ) { if (identifier == NAMETABLE_NIL_ID) return NULL; if (nameTable(identifier,bindings) == NULL){ return NULL; }; if (nameTable(identifier,bindings)->bindingLevel < currentLevel) { return NULL; }; return nameTable(identifier,bindings)->theBinding; } /*--------------------------------------------------------------------*/ /* * Function: Pushes a new scoping level. * * Inputs: * * Outputs: * * Functional Value: void * * Notes: Aborts with an error if too many levels are pushed. * */ void NAMETABLE_push_level (void) { if (currentLevel < MAX_LEVELS) levelStack[++currentLevel] = NULL; else error(NIDL_SCOPELVLS); } /*--------------------------------------------------------------------*/ /* * Function: Pops a scoping level. * * Inputs: * * Outputs: * * Functional Value: void * * Notes: Aborts with an error if there are no more levels. * */ void NAMETABLE_pop_level (void) { NAMETABLE_binding_n_t * bp; NAMETABLE_binding_n_t * obp; NAMETABLE_id_t hsp; if (currentLevel == 0) INTERNAL_ERROR ("Attempt to pop symbol table too many times"); bp = levelStack[currentLevel--]; while (bp) { hsp = bp->boundBy; hsp->bindings = bp->oldBinding; obp = bp; bp = obp->nextBindingThisLevel; FREE (obp); } } /*--------------------------------------------------------------------*/ /* * Function: Enters a string into the string table * * Inputs: * * Outputs: * * Functional Value: The STRTAB identifier for this string. * * Notes: * */ STRTAB_str_t STRTAB_add_string ( const char * string ) { return NAMETABLE_add_id(string); } /*--------------------------------------------------------------------*/ /* * Function: Given a string ID, returns the corresponding string * * Inputs: id - a previously obtained string id * * Outputs: strp - a pointer to corresponding string is return here. * * Functional Value: void * * Notes: * */ void STRTAB_str_to_string ( STRTAB_str_t str, const char ** strp ) { NAMETABLE_id_to_string(str, strp); } /*--------------------------------------------------------------------*/ /* * Function: Initialize the name table. * * Inputs: * * * Outputs: * * Functional Value: * * Notes: * */ void NAMETABLE_init () { NAMETABLE_root = NULL; NAMETABLE_temp_chain = NULL; NAMETABLE_unbalanced = 0; NAMETABLE_names_are_temporary = FALSE; /* * Initialize the binding level stack pointer */ currentLevel = 0; } /*--------------------------------------------------------------------*/ /* * * Function: Given a nametable id and a string, creates a new * nametable entry with the name dentoed by the id * concatenated with the given string. * * Inputs: id - a nametable id. * suffix - a string to be added to the name. * * Outputs: * * Functional value: the new nametable id. * */ NAMETABLE_id_t NAMETABLE_add_derived_name ( NAMETABLE_id_t identifier, const char * matrix ) { char new_name[max_string_len]; char const *old_name_p; NAMETABLE_id_to_string (identifier, &old_name_p); sprintf (new_name, matrix, old_name_p); return NAMETABLE_add_id (new_name); } NAMETABLE_id_t NAMETABLE_add_derived_name2 ( NAMETABLE_id_t identifier1, NAMETABLE_id_t identifier2, char * matrix ) { char new_name[max_string_len]; char const *old_name1_p; char const *old_name2_p; NAMETABLE_id_t id1, id2; id1 = identifier1; id2 = identifier2; NAMETABLE_id_to_string (id1, &old_name1_p); NAMETABLE_id_to_string (id2, &old_name2_p); sprintf (new_name, matrix, old_name1_p, old_name2_p); return NAMETABLE_add_id (new_name); } void NAMETABLE_set_temp_name_mode ( void ) { /* * Bugcheck if already in temporary mode. */ if (NAMETABLE_names_are_temporary) INTERNAL_ERROR ("Recursive entry to temp name mode"); /* * Set temporary mode. */ NAMETABLE_names_are_temporary = TRUE; } void NAMETABLE_set_perm_name_mode ( void ) { /* * Clear temporary mode. */ NAMETABLE_names_are_temporary = FALSE; } void NAMETABLE_clear_temp_name_mode ( void ) { NAMETABLE_temp_name_t * This, * next; /* * Bugcheck if not in temporary mode. */ if (!NAMETABLE_names_are_temporary) INTERNAL_ERROR ("Not in temp name mode"); /* * Walk the list of temp name blocks, freeing the name and then the block. */ for (This = NAMETABLE_temp_chain; This != NULL; ) { NAMETABLE_delete_node (This->node); next = This->next; FREE (This); This = next; } /* * Balance the nametable after all these deletions. */ NAMETABLE_balance_tree(); /* * Clear the temporary flag and the chain head. */ NAMETABLE_names_are_temporary = FALSE; NAMETABLE_temp_chain = NULL; } /* preverve coding style vim: set sw=4 tw=78 : */