/* 
 * Motif
 *
 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with these librararies and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
*/ 
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$XConsortium: UilP2Reslv.c /main/11 1995/07/14 09:36:35 drk $"
#endif
#endif

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif


/*
**++
**  FACILITY:
**
**      User Interface Language Compiler (UIL)
**
**  ABSTRACT:
**
**      This module contain the second pass routines for resolving forward
**	references.
**
**--
**/


/*
**
**  INCLUDE FILES
**
**/

#include "UilDefI.h"


/*
**
**  DEFINE and MACRO DEFINITIONS
**
**/



/*
**
**  EXTERNAL VARIABLE DECLARATIONS
**
**/


/*
**
**  GLOBAL VARIABLE DECLARATIONS
**
**/



/*
**
**  OWN VARIABLE DECLARATIONS
**
**/


/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      This function processes forward references from the first pass.
**
**  FORMAL PARAMETERS:
**
**      none
**
**  IMPLICIT INPUTS:
**
**      sym_az_forward_ref_chain
**	sym_az_val_forward_ref_chain
**
**  IMPLICIT OUTPUTS:
**
**      none
**
**  FUNCTION VALUE:
**
**      void
**
**  SIDE EFFECTS:
**
**      error messages may be issued for objects that are still undefined
**	or of the wrong type
**
**--
**/

void	sem_resolve_forward_refs()

{
    sym_forward_ref_entry_type		* fwd_entry;
    sym_forward_ref_entry_type		* next_fwd_entry;
    sym_val_forward_ref_entry_type	* fwd_val_entry;
    sym_val_forward_ref_entry_type	* next_fwd_val_entry;
    sym_widget_entry_type		** target_obj_entry;
    sym_value_entry_type		** target_val_entry;
    sym_parent_list_type        	* parent_node;
    sym_parent_list_type        	* parent_ptr;
    int                         	found;

    /* 
    **	Forward references are placed on a chain by the first pass of
    **	the compiler.  This routine walks the chain checking that
    **	    1) name is now defined
    **	    2) name points to the correct type of object
    */

    for (fwd_entry = sym_az_forward_ref_chain;  
	 fwd_entry != NULL;  
	 fwd_entry = next_fwd_entry)
    {
	sym_name_entry_type	* name_entry;
	sym_widget_entry_type	* object_entry;
	unsigned short int	object_type;


	/*
	**  Save the pointer to the next forward entry so we can free the current 
	**  entry after it is processed.
	*/
	next_fwd_entry = fwd_entry->az_next_ref;


	/*
	**  Call the Status callback routine to report our progress.
	*/
	/* %COMPLETE */
	Uil_percent_complete = 60;
	if (Uil_cmd_z_command.status_cb != (Uil_continue_type(*)())NULL)
	    diag_report_status();    


	object_type = fwd_entry->header.b_type;
	name_entry = fwd_entry->az_name;
	object_entry = (sym_widget_entry_type *) name_entry->az_object;

	if (object_entry == NULL)
	{
	    diag_issue_diagnostic
		( d_never_def,
		  _sar_source_pos2 (fwd_entry),
		  diag_object_text( object_type ),
		  name_entry->c_text );
	    continue;
	}

	/*
	** Make sure object references are to correct type of object.
	** A forward reference naming a widget class may be correctly
	** resolved by the corresponding gadget class, and vice versa.
	*/
	if ((object_entry->header.b_type!=object_type) &&
	    (uil_gadget_variants[(int)object_entry->header.b_type]!=object_type) &&
	    (uil_gadget_variants[object_type]!=object_entry->header.b_type))
	    {
	    diag_issue_diagnostic
		(d_ctx_req,
		 _sar_source_pos2(fwd_entry),
		 diag_object_text(object_type),
		 diag_object_text(object_entry->header.b_type));
	    continue;
	    }

	target_obj_entry =
		(sym_widget_entry_type * *) fwd_entry->a_update_location;
	*target_obj_entry = object_entry;

	/*
	** Update objects on forward refernce chain so that their parent_lists point
	** to the objects which reference them
	*/
	if (fwd_entry -> parent != NULL)
	    {
	    found = FALSE;
	    for (parent_ptr = object_entry -> parent_list;
		((parent_ptr != NULL) && (found == FALSE));
		parent_ptr = parent_ptr -> next)
		{
		if (parent_ptr -> parent == fwd_entry -> parent)
		    found = TRUE;
		}
	    if (found == FALSE)
		{
		parent_node = (sym_parent_list_type *) 
		    sem_allocate_node (sym_k_parent_list_entry, 
		    sym_k_parent_list_size);
		parent_node -> next = object_entry -> parent_list;
		object_entry -> parent_list = parent_node;
		parent_node -> parent = fwd_entry -> parent;
		}
	    }


	/*
	**  Free the Forward reference entry now that it is no longer needed
	*/    
	sem_free_node(( sym_entry_type *)fwd_entry);

    }


    /*
    **  Now resolve the forward references to values
    **/

    /* 
    **	Forward references are placed on a chain by the first pass of
    **	the compiler.  This routine walks the chain checking that
    **	    1) name is now defined
    **	    2) name points to the correct type of value
    */

    for (fwd_val_entry = sym_az_val_forward_ref_chain;  
	 fwd_val_entry != NULL;  
	 fwd_val_entry = next_fwd_val_entry)
    {
	sym_name_entry_type	* name_entry;
	sym_value_entry_type	* value_entry;
	sym_obj_entry_type	* obj_entry;


	/*
	**  Save the pointer to the next forward entry so we can free the current 
	**  entry after it is processed.
	*/
	next_fwd_val_entry = fwd_val_entry->az_next_ref;


	/*
	**  Call the Status callback routine to report our progress.
	*/
	/* %COMPLETE */
	Uil_percent_complete = 60;
	if (Uil_cmd_z_command.status_cb != (Uil_continue_type(*)())NULL)
	    diag_report_status();    

	name_entry = fwd_val_entry->az_name;
	value_entry = (sym_value_entry_type *) name_entry->az_object;
	obj_entry = (sym_obj_entry_type *) name_entry->az_object;

	if (value_entry == NULL)
	{
	    diag_issue_diagnostic
		( d_never_def,
		  _sar_source_pos2 (fwd_val_entry),
		  "value",
		  name_entry->c_text );
	    continue;
	}

	switch (fwd_val_entry->fwd_ref_flags)
	    {
	    case (sym_k_patch_add):
	    case (sym_k_patch_list_add):
		{
    	        target_val_entry =
		        (sym_value_entry_type * *) fwd_val_entry->a_update_location;
	        *target_val_entry = value_entry;
	        break;
	        }
	    default:
		_assert(FALSE, "Illegal forward reference");
            }


	/*
	**  Free the Forward reference entry now that it is no longer needed
	*/    
	sem_free_node(( sym_entry_type *)fwd_val_entry);

    }




}
