/*
 * CDE - Common Desktop Environment
 *
 * Copyright (c) 1993-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 libraries and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
 */

/*
 * $XConsortium: stubs_c_file.c /main/3 1995/11/06 18:13:48 rswiston $
 * 
 * @(#)stubs_c_file.c	3.48 11 Feb 1994	cde_app_builder/src/abmf
 * 
 * RESTRICTED CONFIDENTIAL INFORMATION:
 * 
 * The information in this document is subject to special restrictions in a
 * confidential disclosure agreement between HP, IBM, Sun, USL, SCO and
 * Univel.  Do not distribute this document outside HP, IBM, Sun, USL, SCO,
 * or Univel without Sun's specific written approval.  This document and all
 * copies and derivative works thereof must be returned or destroyed at Sun's
 * request.
 * 
 * Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
 * 
 */


/*
 * Create a file containing callback proc stubs. These are example notify
 * procedures that will serve as a template for the actual notify procedures
 * in the application.
 */

#include <sys/param.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <ab/util_types.h>
#include <ab_private/abio.h>
#include <ab_private/trav.h>
#include <ab_private/objxm.h>
#include "abmfP.h"
#include "ui_header_fileP.h"
#include "cdefsP.h"
#include "motifdefsP.h"
#include "obj_namesP.h"
#include "utilsP.h"
#include "instancesP.h"
#include "argsP.h"
#include "connectP.h"
#include "write_cP.h"
#include "lib_func_stringsP.h"
#include "stubs_c_fileP.h"

typedef void *VoidPtr;

/*
 * Action argument type.
 */
typedef enum
{
    IMMED_TYPE,
    INT_TYPE,
    STRING_TYPE
}                   ARG_TYPES;

/*
 * REMIND: some time in the future, "instance" should be "dtbTarget"
 */
static STRING	fromVarName = "dtbSource";
static STRING	toVarName = "dtbTarget";
static STRING	instanceVarName = "instance";

/*
 * Data
 */
static STRING	begin_tt_callback_body =
"\nBoolean\n\
%s(Tt_message msg, void *calldata)\n";

static STRING	begin_ss_save_callback_body =
"\nBoolean\n\
%s(Widget widget, String session_file, char ***argv, int *argc)\n";

static STRING	begin_ss_restore_callback_body =
"\nBoolean\n\
%s(Widget widget, char *session_file)\n";

/*
 * Local functions.
 */
static int	printf_setval(GenCodeInfo, ABObj, ...);
static int	printf_getval(GenCodeInfo, ABObj, int nres, ...);
static int write_tooltalk_cb_vars(GenCodeInfo genCodeInfo, ABObj action);
static int write_tooltalk_cb_body1(GenCodeInfo genCodeInfo, ABObj action);
static int write_tooltalk_cb_body2(GenCodeInfo genCodeInfo, ABObj action);
static int write_tooltalk_msg_reply(File codeFile);
static int write_ss_cb_vars(GenCodeInfo genCodeInfo, ABObj action);
static int write_ss_cb_body1(GenCodeInfo genCodeInfo, ABObj action);
static int write_ss_cb_body2(GenCodeInfo genCodeInfo, ABObj action);
static int	write_instance_ptr_var(
			GenCodeInfo	genCodeInfo,  
			ABObj		ipObj,
			STRING		instanceVarName,
			STRING		paramName,
			BOOL		castValue,
			STRING		comment
		);

static int write_builtin_action_for_ref(
                        GenCodeInfo       genCodeInfo, 
                        ABObj             action,
                        ABObj             toObj,
			BOOL              setUpVars,
                        AB_BUILTIN_ACTION builtin_action,
                        STRING            actionTKResource,
                        STRING            actionResource
);

static int write_builtin_action(
                        GenCodeInfo       genCodeInfo, 
                        ABObj             action,
                        ABObj             toObj,
                        AB_BUILTIN_ACTION builtin_action,
                        STRING            actionTKResource,
                        STRING            actionResource
);

/*
 * Gets the object that the connection is "actually" from. If write_conn*
 * is called on an object that has references to it, it's actually the
 * references that have the connections, not the object, itself.
 * (e.g., menus never have connections written, it's the menu references
 * that do).
 */
static ABObj
get_actual_from_obj(ABObj actionOrObj)
{
    static ABObj	lastFromObj = NULL;
    static ABObj	lastActualFromObj = NULL;
    AB_TRAVERSAL	refTrav;
    ABObj		refObj = NULL;
    ABObj		module = NULL;
    ABObj		fromObj = NULL;
    ABObj		actualFromObj = NULL;

    if (actionOrObj == NULL)
    {
	return NULL;
    }

    /*
     * Get the "from" obj
     */
    if (obj_is_action(actionOrObj))
    {
	fromObj = obj_get_from(actionOrObj);
    }
    else if (obj_is_ui(actionOrObj))
    {
	fromObj = actionOrObj;
    }

    /*
     * Shortcut, to avoid a lengthy traversal
     */
    if (fromObj == lastFromObj)
    {
	goto epilogue;
    }

    /*
     * See if we can do anything
     */
    if (fromObj == NULL)
    {
	return NULL;
    }
    module = obj_get_module(fromObj);

    /*
     * Actually find it!
     */
    if (   (!obj_is_ref(fromObj))
        && (   (obj_get_type(fromObj) == AB_TYPE_MENU)
            || (obj_get_parent_of_type(fromObj, AB_TYPE_MENU) != NULL)) )
    {
        /* find an object that references this one, to
         * get the appropriate type (only menu references are 
         * supported, currently).
         */
        for (trav_open(&refTrav, module, AB_TRAV_UI);
	        (refObj = trav_next(&refTrav)) != NULL; )
        {
            if (refObj->ref_to == fromObj)
            {
	        break;
            }
        }
        trav_close(&refTrav);
    }

    if (actualFromObj == NULL)
    {
	if (refObj != NULL)
	{
	    actualFromObj = refObj;
	}
	else
	{
	    actualFromObj = fromObj;
	}
    }

    lastFromObj = fromObj;
    lastActualFromObj = actualFromObj;

epilogue:
    return lastActualFromObj;
}


static BOOL
cwd_is_dtbuilder_src_dir(void)
{
    static BOOL		initialized = FALSE;
    static BOOL		isSrcDir = FALSE;

    if (!initialized)
    {
	initialized = TRUE;
        isSrcDir = (util_paths_are_same_file(".", "../../src/ab"));
    }

    return isSrcDir;
}


static STRING
get_to_var_name(void)
{
    return (cwd_is_dtbuilder_src_dir()? instanceVarName:toVarName);
}


static STRING
get_from_var_name(void)
{
    return fromVarName;
}


/*
 * Generate XtVaSetvalues calls in callbacks.
 * obj is the object that will have it's resources set.
 *
 * Resource list must be name,value pairs, NULL-terminated
 * All resource values must be of type (void *)
 */
static int
printf_setval(GenCodeInfo genCodeInfo, ABObj obj, ...)
{
    int			return_value = 0;
    File		codeFile = genCodeInfo->code_file;
#if defined(__linux__) || defined(CSRG_BASED)
/* Define va_list in <va_list.h> as structure of char ** and int
 * Sun define va_list as void * */
    va_list             paramList = { 0, 0 };
#else
    va_list             paramList = NULL;
#endif /* linux */
    STRING              resName = NULL;
    void		*resValue = NULL;
    STRING		objCName = NULL;
    ISTRING		istrValue = NULL;

    va_start(paramList, obj);
    
    objCName = abmfP_get_c_name(genCodeInfo, obj);
    abio_printf(codeFile, "\tXtVaSetValues(%s,", objCName);
    abio_printf(codeFile, "\n\t\t");

    while ((resName = va_arg(paramList, STRING)) != NULL)
    {
	resValue = va_arg(paramList, VoidPtr);
	switch (abmfP_get_res_type(resName, obj))
	{
	    case AB_ARG_LITERAL:
	    case AB_ARG_PIXEL:
	    case AB_ARG_PIXMAP:
	    case AB_ARG_XMSTRING:
		istrValue = istr_create((STRING)resValue);
		resValue = (VoidPtr)istrValue;
	    break;

	    case AB_ARG_WIDGET:
		util_dprintf(1, 
		    "Ignoring unsupported connection resource type: WIDGET\n");
	    break;
	}
	abmfP_write_arg_val(genCodeInfo, FALSE, resName, resValue, obj);
	abio_printf(codeFile, ",\n\t\t");

	istr_destroy(istrValue);
	resValue = NULL;
    }
    abio_printf(codeFile, "NULL);");

    va_end(paramList);
    return return_value;
}


/*
 * printf_getval - can only get one resource.  This can be changed at a later
 * date if need be. NOTE: We need to declare local variables in one pass,
 * Then write out an XtVaGetValues on a second pass, if we ever want to get
 * more that one value back.
 */
static int
printf_getval(GenCodeInfo genCodeInfo, ABObj obj, int nres,...)
{
    int			return_value = 0;
    File		codeFile = genCodeInfo->code_file;
    va_list             ap;
    STRING              resource;
    ARG_TYPES           type;
    STRING		objCName = NULL;
    nres = nres;		/* avoid warning */

    va_start(ap, nres);

    objCName = abmfP_get_c_name(genCodeInfo, obj);
    resource = va_arg(ap, STRING);
    type = va_arg(ap, ARG_TYPES);

    /* Print the declaration */
    switch (type)
    {
    case IMMED_TYPE:
    case INT_TYPE:
	abio_printf(codeFile, "\tint i;\n\n");
	break;
    case STRING_TYPE:
	abio_printf(codeFile, "\tchar *str;\n\n");
	break;
    }

    abio_printf(codeFile, "\tXtVaGetValues(%s,\n\t\t%s, ", objCName, resource);

    /* Print the local variable reference */
    switch (type)
    {
    case IMMED_TYPE:
    case INT_TYPE:
	abio_printf(codeFile, "&i");
	break;
    case STRING_TYPE:
	abio_printf(codeFile, "&str");
	break;
    }
    abio_printf(codeFile, ",\n\t\tNULL);\n");

    va_end(ap);
    return return_value;
}

static void
set_up_user_type_variables(GenCodeInfo genCodeInfo, ABObj toObj)
{
    File                codeFile = genCodeInfo->code_file;
    ABObj               structObj = abmfP_obj_get_struct_obj(toObj);
    ABObj		winParent = NULL;
    char		winParentName[1024];
    *winParentName = 0;

    /*
     * Determine window parent of this popup
     */
    winParent = obj_get_win_parent(structObj);
    if (winParent == NULL)
    {
	sprintf(winParentName, "%s()", abmfP_lib_get_toplevel_widget->name);
    }
    else
    {
        snprintf(winParentName, sizeof(winParentName), "%s", abmfP_get_c_name(genCodeInfo, winParent));
    }

    /*
     * REMIND: This is obsolete and should be removed!
     */
    if (cwd_is_dtbuilder_src_dir())
    {
        write_instance_ptr_var(genCodeInfo, toObj,
	    instanceVarName, abmfP_client_data_var_name, TRUE, NULL);
	abio_puts(genCodeInfo->code_file, nlstr);
    }
    else
    {
        write_instance_ptr_var(genCodeInfo, toObj,
	    toVarName, abmfP_client_data_var_name, TRUE, NULL);
        write_instance_ptr_var(genCodeInfo, toObj,
	    instanceVarName, toVarName, FALSE, "/* obsolete */");
	abio_puts(genCodeInfo->code_file, nlstr);
    }
    abio_printf(codeFile, "if (!(%s->initialized))\n", get_to_var_name());
    abmfP_write_c_block_begin(genCodeInfo);
    abio_printf(codeFile, "%s(%s, %s);\n",
		abmfP_get_init_proc_name(structObj),
		get_to_var_name(),
		winParentName);
    abmfP_write_c_block_end(genCodeInfo);
}


static int
write_instance_ptr_var(
			GenCodeInfo	genCodeInfo,  
			ABObj		ipObj,
			STRING		instanceVarName,
			STRING		paramName,
			BOOL		castValue,
			STRING		comment
)
{
    FILE	*codeFile = genCodeInfo->code_file;

    if (ipObj == NULL)
    {
	return 0;
    }
    abio_printf(genCodeInfo->code_file, "%s\t%s = ",
		abmfP_get_c_struct_ptr_type_name(ipObj),
		instanceVarName);
    if (castValue)
    {
	abio_printf(codeFile, "(%s)", abmfP_get_c_struct_ptr_type_name(ipObj));
    }

    abio_printf(codeFile, "%s;", paramName);

    if (comment != NULL)
    {
	abio_printf(genCodeInfo->code_file, "\t%s", comment);
    }
    abio_puts(genCodeInfo->code_file, nlstr);
    return 0;
}


static int
write_tooltalk_cb_vars(
    GenCodeInfo genCodeInfo,
    ABObj action 
)
{
    File                codeFile;

    if (!genCodeInfo || !action)
        return 0;

    codeFile = genCodeInfo->code_file;

    switch(obj_get_when(action))
    {
	case AB_WHEN_TOOLTALK_QUIT:
	    abio_puts(codeFile, "int\t\tsilent = 0;\n");
	    abio_puts(codeFile, "int\t\tforce = 0;\n");
	    abio_puts(codeFile, "Boolean\t\tcancel = False;\n");
	    break;
	case AB_WHEN_TOOLTALK_GET_STATUS:
	    abio_puts(codeFile, "char\t\t*status_string = \"\";\n");
	    break;
	case AB_WHEN_TOOLTALK_PAUSE_RESUME:
	    abio_puts(codeFile, "Boolean\t\tsensitive = (Bool)calldata;\n");
	    abio_puts(codeFile, "Boolean\t\talready_set = False;\n");
	    break;
	case AB_WHEN_TOOLTALK_DO_COMMAND:
	    abio_puts(codeFile, "Tt_status\t\tstatus = TT_DESKTOP_ENOTSUP;\n");
	    abio_puts(codeFile, "char\t\t*command;\n");
	    abio_puts(codeFile, "char\t\t*result;\n");
	    break;
	default:
	    break;
    }
    return 0;
}

static int
write_tooltalk_cb_body1(
    GenCodeInfo genCodeInfo,
    ABObj action
)
{
    File                codeFile;

    if (!genCodeInfo || !action)
        return 0;
 
    codeFile = genCodeInfo->code_file; 

    switch(obj_get_when(action))
    {
        case AB_WHEN_TOOLTALK_QUIT:
	    abio_puts(codeFile, "tt_message_arg_ival(msg, 0, &silent);\n");
	    abio_puts(codeFile, "tt_message_arg_ival(msg, 1, &force);\n");
	    abio_puts(codeFile,"\n");
            abio_puts(codeFile, abmfP_comment_begin);
            abio_puts(codeFile, abmfP_comment_continue);
            abio_puts(codeFile,
              "Process Quit request->\n");
            abio_puts(codeFile, abmfP_comment_continue);
            abio_puts(codeFile,
                "if \"silent\" == 1, then the Quit should occur without\n");
            abio_puts(codeFile, abmfP_comment_continue);
            abio_puts(codeFile,
		"notifying the user.  If \"force\" == 1, then the user may\n");
            abio_puts(codeFile, abmfP_comment_continue);
            abio_puts(codeFile,
                "be notified, but the Quit should not be cancellable.\n");
            abio_puts(codeFile, abmfP_comment_continue);
            abio_puts(codeFile,
                "If \"silent\" == 0 and \"force\" == 0, then this Quit\n");
            abio_puts(codeFile, abmfP_comment_continue);
            abio_puts(codeFile,
                "request may be cancelled, in which case \"cancel\" should\n");
            abio_puts(codeFile, abmfP_comment_continue);
            abio_puts(codeFile,
                "be set to True in order send the \"failed\" reply.\n");
            abio_puts(codeFile, abmfP_comment_continue); 
            abio_puts(codeFile, 
		"If the Quit request is honored (not cancelled), the\n");
            abio_puts(codeFile, abmfP_comment_continue);  
            abio_puts(codeFile,  
		"application exit should not occur until after the request\n");
            abio_puts(codeFile, abmfP_comment_continue);   
            abio_puts(codeFile,  
		"has been replied-to.\n");
            abio_puts(codeFile, abmfP_comment_end);
            break;

        case AB_WHEN_TOOLTALK_GET_STATUS:
            abio_puts(codeFile, abmfP_comment_begin);
            abio_puts(codeFile, abmfP_comment_continue);
            abio_puts(codeFile,
              "Process Get Status request->\n");
            abio_puts(codeFile, abmfP_comment_continue);
            abio_puts(codeFile,
                "The application should assign \"status_string\" an appropriate\n");
            abio_puts(codeFile, abmfP_comment_continue);
            abio_puts(codeFile,
                "string value reflecting the application's status.\n");
            abio_puts(codeFile, abmfP_comment_end);
            break;
        case AB_WHEN_TOOLTALK_PAUSE_RESUME:
            abio_puts(codeFile, abmfP_comment_begin); 
            abio_puts(codeFile, abmfP_comment_continue); 
            abio_puts(codeFile, 
              "Process Pause/Resume request->\n"); 
            abio_puts(codeFile, abmfP_comment_continue);
            abio_puts(codeFile,  
                "If \"sensitive\" == False (Pause), then the application should\n"); 
            abio_puts(codeFile, abmfP_comment_continue); 
            abio_puts(codeFile,   
                "set the sensitivity on all mapped shells to False.  If\n");  
            abio_puts(codeFile, abmfP_comment_continue);  
            abio_puts(codeFile,    
                "\"sensitive\" == True (Resume), then the application should\n"); 
            abio_puts(codeFile, abmfP_comment_continue);   
            abio_puts(codeFile,     
                "set the sensitivity on all mapped shells to True.n"); 
            abio_puts(codeFile, abmfP_comment_continue);    
            abio_puts(codeFile,      
                "If the application is already in the requested state of\n"); 
            abio_puts(codeFile, abmfP_comment_continue);     
            abio_puts(codeFile,       
		"sensitivity, then \"already_set\" should be set to True.\n");
            abio_puts(codeFile, abmfP_comment_end);
            break;
        case AB_WHEN_TOOLTALK_DO_COMMAND:
            abio_puts(codeFile, "command = tt_message_arg_val(msg, 0);\n");
            abio_puts(codeFile, "\n"); 
    	    abio_puts(codeFile, abmfP_comment_begin);
    	    abio_puts(codeFile, abmfP_comment_continue);
    	    abio_puts(codeFile,
              "Process Do_Command request->\n");
    	    abio_puts(codeFile, abmfP_comment_continue);
	    abio_puts(codeFile, 
		"The application should execute the code defined by \"command\".\n");
            abio_puts(codeFile, abmfP_comment_continue);
            abio_puts(codeFile,  
                "If execution is successful, then \"status\" should be set to TT_OK,\n"); 
            abio_puts(codeFile, abmfP_comment_continue); 
            abio_puts(codeFile,   
		"else set to the appropriate Tt_status value.\n");
            abio_puts(codeFile, abmfP_comment_continue);  
            abio_puts(codeFile,    
		"If the command returns a result, then \"result\" should be set\n");
            abio_puts(codeFile, abmfP_comment_continue);   
            abio_puts(codeFile,     
                "to the appropriate result string.\n"); 
    	    abio_puts(codeFile, abmfP_comment_end);
            break;
        default:
            break;
    }
    abio_puts(codeFile, "\n");
    return 0;
}


static int
write_tooltalk_cb_body2(
    GenCodeInfo genCodeInfo,
    ABObj action
)
{
    File                codeFile;

    if (!genCodeInfo || !action)
        return 0;

    codeFile = genCodeInfo->code_file;

    abio_puts(codeFile, "\n");

    switch(obj_get_when(action))
    {
        case AB_WHEN_TOOLTALK_QUIT:
	    abio_puts(codeFile, "if (cancel == True)\n");
	    abio_indent(codeFile);
	    abio_puts(codeFile, "tttk_message_fail(msg, TT_DESKTOP_ECANCELED, 0, 1);\n");
	    abio_outdent(codeFile);
	    abio_puts(codeFile, "else\n");
	    abio_puts(codeFile, "{\n");
	    abio_indent(codeFile);
	    write_tooltalk_msg_reply(codeFile);
	    abio_puts(codeFile, "\n");

    	    abmfP_write_c_comment(genCodeInfo, FALSE,
        	"Now that the Message has been replied, process Quit operation");
            abmfP_write_user_code_seg(genCodeInfo, NULL);
            abio_puts(codeFile, nlstr);

	    abio_outdent(codeFile);
	    abio_puts(codeFile, "}\n");
            break;
        case AB_WHEN_TOOLTALK_GET_STATUS:
	    abio_puts(codeFile, "tt_message_arg_val_set(msg, 0, status_string);\n");
            write_tooltalk_msg_reply(codeFile);
            break;
        case AB_WHEN_TOOLTALK_PAUSE_RESUME:
	    abio_puts(codeFile, "if (already_set == True)\n");
	    abio_indent(codeFile);
	    abio_puts(codeFile, "tt_message_status_set(msg, TT_DESKTOP_EALREADY);\n");
	    abio_outdent(codeFile);
            write_tooltalk_msg_reply(codeFile);
            break;
        case AB_WHEN_TOOLTALK_DO_COMMAND:
    	    abio_puts(codeFile, "tt_free(command);\n");
    	    abio_puts(codeFile, "tt_message_status_set(msg, status);\n");
    	    abio_puts(codeFile, "if (tt_is_err(status))\n");
	    abio_indent(codeFile);
	    abio_puts(codeFile, "tttk_message_fail(msg, status, 0, 1);\n");
	    abio_outdent(codeFile);
            abio_puts(codeFile, "else\n");
            abio_puts(codeFile, "{\n");
            abio_indent(codeFile);
	    abio_puts(codeFile, "if (result != NULL)\n");
    	    abio_indent(codeFile);
	    abio_puts(codeFile, "tt_message_arg_val_set(msg, 1, result);\n");
	    abio_outdent(codeFile);
            write_tooltalk_msg_reply(codeFile);
	    abio_outdent(codeFile);
            abio_puts(codeFile, "}\n");
            break;
        default:
            break;
    }

    abio_puts(codeFile, nlstr);
    abmfP_write_user_code_seg(genCodeInfo, NULL);
    abio_puts(codeFile, nlstr);
    abio_puts(codeFile, "return True;\n");
    return 0;
}


static int
write_tooltalk_msg_reply(
    File	codeFile
)
{
     abio_puts(codeFile, "tt_message_reply(msg);\n"); 
     abio_puts(codeFile, "tttk_message_destroy(msg);\n"); 

     return 0;
}


static int
write_ss_cb_vars(
    GenCodeInfo genCodeInfo,
    ABObj action 
)
{
    File                codeFile;

    if (!genCodeInfo || !action)
        return 0;

    codeFile = genCodeInfo->code_file;

    switch(obj_get_when(action))
    {
	case AB_WHEN_SESSION_SAVE:
	case AB_WHEN_SESSION_RESTORE:
	    abio_puts(codeFile, "Boolean\t\tret_value = False;\n");
	    break;
	default:
	    break;
    }
    return 0;
}

static int
write_ss_cb_body1(
    GenCodeInfo genCodeInfo,
    ABObj action
)
{
    File                codeFile;

    if (!genCodeInfo || !action)
        return 0;
 
    codeFile = genCodeInfo->code_file; 

    switch(obj_get_when(action))
    {
	case AB_WHEN_SESSION_RESTORE:
    	    abio_puts(codeFile, abmfP_comment_begin);
    	    abio_puts(codeFile, abmfP_comment_continue);
    	    abio_puts(codeFile,
              "Restore application state via session file.\n");
    	    abio_puts(codeFile, abmfP_comment_continue);
    	    abio_puts(codeFile,
              "Use contents of \"session file\" to bring the application\n");
    	    abio_puts(codeFile, abmfP_comment_continue);
    	    abio_puts(codeFile,
              "to the desired state.\n");
    	    abio_puts(codeFile, abmfP_comment_continue);
    	    abio_puts(codeFile,
              "Set \"ret_value\" to True to indicate success.\n");
    	    abio_puts(codeFile, abmfP_comment_end);
            break;
	case AB_WHEN_SESSION_SAVE:
    	    abio_puts(codeFile, abmfP_comment_begin);
    	    abio_puts(codeFile, abmfP_comment_continue);
    	    abio_puts(codeFile,
              "Save application state in either session file and/or\n");
    	    abio_puts(codeFile, abmfP_comment_continue);
	    abio_puts(codeFile, 
		"command line vector.\n");
            abio_puts(codeFile, abmfP_comment_continue);
	    abio_puts(codeFile, "\n");
            abio_puts(codeFile, abmfP_comment_continue);
            abio_puts(codeFile,  
                "Session File:\n"); 
            abio_puts(codeFile, abmfP_comment_continue); 
            abio_puts(codeFile,   
		"    Open the file \"session_file\"\n");
            abio_puts(codeFile, abmfP_comment_continue); 
            abio_puts(codeFile,   
		"    Write application state information into it\n");
            abio_puts(codeFile, abmfP_comment_continue); 
            abio_puts(codeFile,   
		"    Close the file\n");
            abio_puts(codeFile, abmfP_comment_continue); 
            abio_puts(codeFile,   
		"    Set \"ret_value\" to True\n");
            abio_puts(codeFile, abmfP_comment_continue); 
            abio_puts(codeFile,   
		"    (Setting \"ret_value\" to True is important if you are using\n");
            abio_puts(codeFile, abmfP_comment_continue); 
            abio_puts(codeFile,   
		"    session files! Do not set it to True if you are not using\n");
            abio_puts(codeFile, abmfP_comment_continue); 
            abio_puts(codeFile,   
		"    session files.)\n");
            abio_puts(codeFile, abmfP_comment_continue);  
            abio_puts(codeFile,   "\n");
            abio_puts(codeFile, abmfP_comment_continue);  
            abio_puts(codeFile,    
		"Command line vector:\n");
            abio_puts(codeFile, abmfP_comment_continue);   
            abio_puts(codeFile,     
                "    Allocate an argv vector\n"); 
            abio_puts(codeFile, abmfP_comment_continue);   
            abio_puts(codeFile,     
                "    Fill it up with the appropriate strings\n"); 
            abio_puts(codeFile, abmfP_comment_continue);   
            abio_puts(codeFile,     
                "    Return the argv vector in \"argv\" i.e.\n"); 
            abio_puts(codeFile, abmfP_comment_continue);   
            abio_puts(codeFile,     
                "    \t*argv = my_new_argv;\n"); 
            abio_puts(codeFile, abmfP_comment_continue);   
            abio_puts(codeFile,     
                "    Return the size of the vector in argc\n"); 
    	    abio_puts(codeFile, abmfP_comment_end);
            break;
        default:
            break;
    }
    abio_puts(codeFile, "\n");
    return 0;
}


static int
write_ss_cb_body2(
    GenCodeInfo genCodeInfo,
    ABObj action
)
{
    File                codeFile;

    if (!genCodeInfo || !action)
        return 0;

    codeFile = genCodeInfo->code_file;

    abio_puts(codeFile, "\n");
    abio_puts(codeFile, "return ret_value;\n");
    return 0;
}


static int
write_action_functions(GenCodeInfo genCodeInfo, ABObj obj)
{
    File                codeFile = genCodeInfo->code_file;
    static char         msg[256],
                       *s;
    AB_TRAVERSAL        trav;
    ABObj               action = NULL;
    ABObj               fromObj = NULL;	/* for error reports */
    int                 i = 0;

    /*
     * Auto-named functions
     */
    for (trav_open(&trav, obj, AB_TRAV_ACTIONS_FOR_OBJ | AB_TRAV_MOD_SAFE), i = 0;
	 (action = trav_next(&trav)) != NULL; ++i)
    {
	if (   mfobj_has_flags(action, CGenFlagIsDuplicateDef)
	    || mfobj_has_flags(action, CGenFlagWriteDefToProjFile))
	{
	    continue;
	}

	if (action->info.action.auto_named)
	{
	    abmfP_write_action_function(genCodeInfo, action);
	    abio_puts(genCodeInfo->code_file, "\n");
	}
    }
    /* don't close traversal, yet */

    /*
     * User-named functions
     */
    for (trav_reset(&trav);
	 (action = trav_next(&trav)) != NULL; ++i)
    {
	if (   mfobj_has_flags(action, CGenFlagIsDuplicateDef)
	    || mfobj_has_flags(action, CGenFlagWriteDefToProjFile))
	{
	    continue;
	}

	if (!(action->info.action.auto_named))
	{
	    abmfP_write_action_function(genCodeInfo, action);
	    abio_puts(genCodeInfo->code_file, "\n");
	}
    }
    trav_close(&trav);

    return OK;
}


/*
 * Write the callback proc stub file.
 */
int
abmfP_write_stubs_c_file(
			 GenCodeInfo genCodeInfo,
			 STRING codeFileName,
			 ABObj module
)
{
    File                codeFile = genCodeInfo->code_file;
    STRING              errmsg = NULL;
    ABObj               win_obj = NULL;
    ABObj               project = obj_get_project(module);
    char		moduleHeaderFileName[MAX_PATH_SIZE];
    char		moduleName[MAX_PATH_SIZE];

    /*
     * Write file header.
     */

    abmfP_write_user_header_seg(genCodeInfo);
    abio_puts(codeFile, nlstr);

    sprintf(moduleName, "module %s", obj_get_name(module));
    abmfP_write_file_header(
		genCodeInfo, 
		codeFileName, 
		FALSE,
		moduleName,
		util_get_program_name(), 
		ABMF_MODIFY_USER_SEGS,
	   " * Contains: Module callbacks and connection functions"
		);


    /*
     * Write includes.
     */
    strcpy(moduleHeaderFileName, abmfP_get_ui_header_file_name(module));
    abmfP_write_c_system_include(genCodeInfo, "stdint.h");
    abmfP_write_c_system_include(genCodeInfo, "stdio.h");
    abmfP_write_c_system_include(genCodeInfo, "Xm/Xm.h");
    abmfP_write_c_local_include(genCodeInfo, 
			abmfP_get_utils_header_file_name(module));

    /* 
     * Include project file if i18n is enabled. This file
     * is needed for the message catalog stuff
     */
    if (genCodeInfo->i18n_method == ABMF_I18N_XPG4_API)
        abmfP_write_c_local_include(genCodeInfo,
	    abmfP_get_project_header_file_name(project));
    abmfP_write_c_local_include(genCodeInfo, moduleHeaderFileName);
		    

    /*
     * Write out includes for modules with connection targets
     */
    {
	StringListRec       connIncludes;
	int                 i = 0;
	int                 num_strings = 0;
	strlist_construct(&connIncludes);

	strlist_add_str(&connIncludes, moduleHeaderFileName, NULL);
	abmfP_get_connect_includes(&connIncludes, module);
	num_strings = strlist_get_num_strs(&connIncludes);
	if (num_strings > 1)		/* start at 1 - skip this_ui.h */
	{
            abio_puts(codeFile, nlstr);
	    abmfP_write_c_comment(genCodeInfo, FALSE,
		"Header files for cross-module connections");
	}
	for (i = 1; i < num_strings; ++i)
	{
	    abio_printf(codeFile, "#include %s\n",
				  strlist_get_str(&connIncludes, i, NULL));
	}

	strlist_destruct(&connIncludes);
    }
    abio_puts(codeFile, nlstr);

    abmfP_write_user_file_top_seg(genCodeInfo);
    abio_puts(codeFile, nlstr);

    if (write_action_functions(genCodeInfo, module) != OK)
	return ERROR;

    abmfP_write_user_file_bottom_seg(genCodeInfo);
    return OK;
}


int
abmfP_write_action_function(
			GenCodeInfo	genCodeInfo, 
			ABObj		action
)
{
    int			rc = 0;			/* return code */
    BOOL		isTTCB = FALSE;
    BOOL		ss_cb = FALSE;
    File                codeFile = genCodeInfo->code_file;
    BOOL		topUserSegWritten = FALSE;
    BOOL		bottomUserSegWritten = FALSE;
    BOOL		funcBodyWritten = FALSE;
    BOOL		funcEndWritten = FALSE;
    BOOL		actionPrintfWritten = FALSE;
    int                 return_value = 0;
    ABObj               fromObj = obj_get_from(action);
    ABObj		actualFromObj = NULL;
    ABObj		toObj = obj_get_to(action);
    ABObj		module = NULL;
    char		actionName[1024];
    char		actionPrintf[32 + sizeof(actionName)];

    abmfP_gencode_enter_func(genCodeInfo);
    abmfP_ip_obj(genCodeInfo) = obj_get_to(action);
    util_strncpy(actionName, abmfP_get_action_name(action), 1024);
    sprintf(actionPrintf, "printf(\"action: %s()\\n\");\n", actionName);

    /***
     *** START OF FUNCTION
     ***/

    switch (obj_get_when(action))
    {
    case AB_WHEN_AFTER_CREATED:
	/* 
	 * post-create procs have the signature of an Xt Callback,
	 * although they are called as conventional functions.
	 */
        fromObj = obj_get_from(action);
	actualFromObj = get_actual_from_obj(action);
        abmfP_write_xm_callback_begin(genCodeInfo, FALSE, actionName);
        write_instance_ptr_var(genCodeInfo, actualFromObj,
	    get_from_var_name(), "callData", TRUE, NULL);
	abio_puts(genCodeInfo->code_file, nlstr);

    break;

    case AB_WHEN_DRAGGED_FROM:
    {
	abio_printf(genCodeInfo->code_file, 
	    abmfP_lib_default_dragCB->def,	/* this is a format string */
		actionName,actionName,actionName,
		actionName,actionName, actionName);
	abio_puts(genCodeInfo->code_file, "\n\n");

	/* these are all in the "library" definition */
	topUserSegWritten = TRUE;
	bottomUserSegWritten = TRUE;
	funcBodyWritten = TRUE;
	funcEndWritten = TRUE;
	actionPrintfWritten = TRUE;
    }
    break;

    case AB_WHEN_DROPPED_ON:
    {
	abio_printf(genCodeInfo->code_file, 
	    abmfP_lib_default_dropCB->def,	/* this is a format string */
		actionName,actionName,actionName,actionName);
	abio_puts(genCodeInfo->code_file, "\n\n");

	/* these are all in the "library" definition */
	topUserSegWritten = TRUE;
	bottomUserSegWritten = TRUE;
	funcBodyWritten = TRUE;
	funcEndWritten = TRUE;
	actionPrintfWritten = TRUE;
    }
    break;

    case AB_WHEN_TOOLTALK_QUIT:
    case AB_WHEN_TOOLTALK_DO_COMMAND:
    case AB_WHEN_TOOLTALK_GET_STATUS:
    case AB_WHEN_TOOLTALK_PAUSE_RESUME:
	isTTCB = TRUE;
	    abio_printf(codeFile, begin_tt_callback_body, actionName);
            abmfP_write_c_block_begin(genCodeInfo);
            write_tooltalk_cb_vars(genCodeInfo, action);
    break;

    case AB_WHEN_SESSION_RESTORE:
	ss_cb = TRUE;
	    abio_printf(codeFile, begin_ss_restore_callback_body,
		abmfP_get_action_name(action));
            abmfP_write_c_block_begin(genCodeInfo);
            write_ss_cb_vars(genCodeInfo, action);
    break;

    case AB_WHEN_SESSION_SAVE:
	ss_cb = TRUE;
	    abio_printf(codeFile, begin_ss_save_callback_body,
		abmfP_get_action_name(action));
            abmfP_write_c_block_begin(genCodeInfo);
            write_ss_cb_vars(genCodeInfo, action);
    break;

    default:
        abmfP_write_xm_callback_begin(genCodeInfo, FALSE, actionName);
    break;

    } /* switch obj_get_when() */


    /***** 
     ***** TOP USER SEGMENT
     *****/

    if (!topUserSegWritten)
    {
	STRING	contents = 
	    	    (actionPrintfWritten? NULL:(isTTCB? actionPrintf:NULL));
        abmfP_write_user_var_and_code_seg(genCodeInfo, contents);
        abio_puts(codeFile, nlstr);
	topUserSegWritten = TRUE;
	if (contents != NULL)
	{
	    actionPrintfWritten = TRUE;
	}
    }

    /***
     *** FUNCTION BODY
     ***/

    if (isTTCB)
    {
        write_tooltalk_cb_body1(genCodeInfo, action);
        abmfP_write_user_code_seg(genCodeInfo, NULL);
        write_tooltalk_cb_body2(genCodeInfo, action);
	funcBodyWritten = TRUE;
	bottomUserSegWritten = TRUE; 
    }
    else if (ss_cb)
    {
        write_ss_cb_body1(genCodeInfo, action);
        abmfP_write_user_code_seg(genCodeInfo, NULL);
        write_ss_cb_body2(genCodeInfo, action);
	funcBodyWritten = TRUE;
	bottomUserSegWritten = TRUE;
    }
    else if (!funcBodyWritten) switch (obj_get_func_type(action))
    {
    case AB_FUNC_BUILTIN:
	rc = abmfP_write_builtin_action(genCodeInfo, action, TRUE);
	return_if_err(rc,rc);
	funcBodyWritten = TRUE;
	break;

    case AB_FUNC_USER_DEF:
	abmfP_write_user_start_comment(genCodeInfo, "vvv Add C code below vvv");
	abmfP_write_user_end_comment(genCodeInfo, "^^^ Add C code above ^^^");
	bottomUserSegWritten = TRUE;
	funcBodyWritten = TRUE;
	break;

    case AB_FUNC_CODE_FRAG:
	abio_puts(codeFile, obj_get_func_code(action));
	funcBodyWritten = TRUE;
	break;

    case AB_FUNC_ON_ITEM_HELP:
	abio_printf(codeFile, "dtb_do_onitem_help();\n");
	funcBodyWritten = TRUE;
	break;

    case AB_FUNC_HELP_VOLUME:
	abio_printf(codeFile, 
		"dtb_show_help_volume_info(\"%s\", \"%s\");\n",
		istr_string(action->info.action.volume_id), 
		istr_string(action->info.action.location));
	funcBodyWritten = TRUE;
	break;

    default:
	{
	    char *obj_name_string = obj_get_name(fromObj);
	    util_printf_err(CATGETS(Dtb_project_catd, 1, 78,
		    "unknown function type for action from object, %s"),
		    obj_name_string);
	    return_code(ERR);
	}
	break;
    }

    /***** 
     ***** BOTTOM USER SEGMENT
     *****/

    if (!bottomUserSegWritten)
    {
	STRING	contents = (actionPrintfWritten? NULL:actionPrintf);
	abmfP_write_user_code_seg(genCodeInfo, contents);
	bottomUserSegWritten = TRUE;
	if (contents != NULL)
	{
	    actionPrintfWritten = TRUE;
	}
    }

    /***** 
     ***** FUNCTION END 
     *****/

    if (!funcEndWritten)
    {
        abmfP_write_c_func_end(genCodeInfo, NULL);
	funcEndWritten = TRUE;
    }

epilogue:
    abmfP_gencode_exit_func(genCodeInfo);
    return return_value;
}


int
abmfP_write_builtin_action(
			GenCodeInfo	genCodeInfo, 
			ABObj 		action,
			BOOL		setUpVars
)
{
    int			return_value     = 0;
    File                codeFile         = genCodeInfo->code_file;
    ABObj               toObj            = NULL;
    STRING		actionTKResource = NULL;	/* in toolkit */
    STRING		actionResource   = NULL;	/* in source code */
    ISTRING		istr_resource    = NULL;
    AB_BUILTIN_ACTION	builtin_action   = AB_STDACT_UNDEF;

    toObj          = obj_get_to(action);
    builtin_action = obj_get_func_builtin(action);
    if (toObj != NULL)
    {
        toObj = objxm_comp_get_target_for_builtin_action(toObj, builtin_action);
    }
    if (toObj == NULL)
    {
	abmfP_write_c_comment(genCodeInfo, FALSE, "Invalid action ignored.");
	abio_puts(codeFile, nlstr);
	return 0;
    }

    /*
     * We need to convert the resource into a string that can be put
     * in the .c file.
     */
    actionTKResource = objxm_get_resource_for_builtin_action(
				toObj, builtin_action);
    istr_resource    = objxm_get_res_strname(actionTKResource);
    actionResource   = istr_string(istr_resource);

    if (abmfP_get_c_name(genCodeInfo, toObj) == NULL)
    {
	return_value = write_builtin_action_for_ref(genCodeInfo,
	    action, toObj, setUpVars, builtin_action, actionTKResource,
	    actionResource);
    }
    else
    {
	if (setUpVars)
	{
	    set_up_user_type_variables(genCodeInfo, toObj);
	}
	
	return_value = write_builtin_action(genCodeInfo, action, toObj,
	    builtin_action, actionTKResource, actionResource);
    }

    if (return_value == 0)
	abio_printf(codeFile, nlstr);
	
epiloge:
    abio_printf(codeFile, nlstr);
    return return_value;
}


/*
** we are on a virtual object and need to write the actual builtin action
** for each ref to it.
*/
static int
write_builtin_action_for_ref(
    GenCodeInfo	      genCodeInfo, 
    ABObj 	      action,
    ABObj             toObj,
    BOOL              setUpVars,
    AB_BUILTIN_ACTION builtin_action,
    STRING            actionTKResource,		       /* in toolkit */
    STRING	      actionResource		       /* in source code */
)
{
    int                        i = 0;
    int                  numRefs = 0;
    int             return_value = 0;
    ABObj                 refObj = NULL;
    ABObjList            refList = NULL;
	
    if (!genCodeInfo || !action || !toObj)
	return -1;
    
    refList = abmfP_find_refs_to(toObj);
    numRefs = objlist_get_num_objs(refList);
    
    if ((refList != NULL) && (numRefs > 0))
    {
	if (setUpVars)
	{
	    refObj = objlist_get_obj(refList, 0, NULL);
	    set_up_user_type_variables(genCodeInfo, refObj);
	}
	    
	/* write the builtin actions */
	for (i = 0; i < numRefs; ++i)
	{
	    refObj  = objlist_get_obj(refList, i, NULL);

	    if (abmfP_get_c_name(genCodeInfo, refObj) != NULL)
	    {
		return_value = write_builtin_action(genCodeInfo,
		    action, refObj, builtin_action, actionTKResource,
		    actionResource);
	    }
	}
    }
    else
    {
	util_dprintf(0, "ERROR: write_builtin_action_for_ref(): ");
	util_dprintf(0, "Unable to obtain references to the object.\n");
    }

epiloge:
    objlist_destroy(refList);
    return return_value;
}


/*
** determine which builtin action and write the appropriate code.
*/
static int
write_builtin_action(
    GenCodeInfo	      genCodeInfo, 
    ABObj 	      action,
    ABObj             toObj,
    AB_BUILTIN_ACTION builtin_action,
    STRING            actionTKResource,		       /* in toolkit */
    STRING	      actionResource		       /* in source code */
)
{
#define	 IS(type)	(obj_get_func_type(action) ==(type))
#define	 SVAL(action)	((STRING)obj_get_arg_string(action))
#define	 IVAL(action)	((int)obj_get_arg_int(action))

    File                codeFile     = genCodeInfo->code_file;
    int			return_value = 0;

    if (!codeFile || !action || !toObj || !builtin_action)
	return return_value;

    switch (builtin_action)
    {
	case AB_STDACT_ENABLE:
	    abio_print_line(codeFile, NULL);
	    abio_print_line(codeFile, "XtSetSensitive(%s, True);",
		abmfP_get_c_name(genCodeInfo, toObj));
	    break;

	case AB_STDACT_DISABLE:
	    abio_print_line(codeFile, NULL);
	    abio_print_line(codeFile, "XtSetSensitive(%s, False);",
		abmfP_get_c_name(genCodeInfo, toObj));
	    break;

	case AB_STDACT_SHOW:
	    switch((obj_get_root(toObj))->type)
	    {
		case AB_TYPE_BASE_WINDOW:
		    abio_print_line(codeFile, "XtPopup(%s, XtGrabNone);",
			abmfP_get_c_name(genCodeInfo, toObj));
		    break;
			
		case AB_TYPE_DIALOG: 
		case AB_TYPE_FILE_CHOOSER: 
		default:
		    abio_print_line(codeFile, "XtManageChild(%s);",
			abmfP_get_c_name(genCodeInfo, toObj));
		    break;
	    }
	    break;

	case AB_STDACT_HIDE:
	    switch((obj_get_root(toObj))->type) 
	    { 
		case AB_TYPE_BASE_WINDOW: 
		    abio_print_line(codeFile, "XtPopdown(%s);",
			abmfP_get_c_name(genCodeInfo, toObj));
		    break;

		case AB_TYPE_DIALOG:  
		case AB_TYPE_FILE_CHOOSER:  
		default:
		    abio_print_line(codeFile, "XtUnmanageChild(%s);",
			abmfP_get_c_name(genCodeInfo, toObj));
		    break;
	    }
	    break;

	case AB_STDACT_SET_LABEL:
	    /* check toObj for root */
	    if ( obj_get_label_type(obj_get_root(toObj)) == AB_LABEL_GLYPH)
	    {
		abio_printf(codeFile, "%s(%s, ",
		    abmfP_lib_set_label_from_image_file->name,
		    abmfP_get_c_name(genCodeInfo, toObj));
		abio_put_string(codeFile, SVAL(action));
		abio_puts(codeFile, ");\n");
	    }
	    else
	    {
		assert(actionTKResource != NULL);
		printf_setval(genCodeInfo, toObj,
		    actionTKResource, SVAL(action),
		    NULL);
	    }
	    break;

	case AB_STDACT_SET_VALUE:
	    printf_setval(genCodeInfo, toObj, 
		actionTKResource, IVAL(action), NULL);
	    break;

	case AB_STDACT_SET_TEXT:
	    printf_setval(genCodeInfo, toObj, 
		actionTKResource, SVAL(action),
		NULL);
	    break;

/* 	case AB_STDACT_SHOW_HELP: */
/* 	    abio_print_line(codeFile, NULL); */
/* 	    abio_print_line(codeFile,  */
/* 		"XtCallCallbacks(%s,XmNhelpCallback,(XtPointer)NULL);", */
/* 		abmfP_get_c_name(genCodeInfo, toObj)); */
/* 	    break; */

	default:
	    {
		static char         msg[255];

		if (obj_get_name(action) != NULL)
		{
		    char *action_name = obj_get_name(action);
		    sprintf(msg, CATGETS(Dtb_project_catd, 1, 76,
			"Unknown action name, %s"), action_name);
		}
		else
		{
		    int action_type = obj_get_func_builtin(action);
		    sprintf(msg, CATGETS(Dtb_project_catd, 1, 77,
			"Unknown action type, %d"), action_type);
		}
		util_error(msg);
		return_value = ERR_INTERNAL;

		/*
		 * return msg; Just print message and go on - JT
		 */
	    }
	    break;
    }			/* switch func.value.builtin */

    return return_value;
#undef IS
#undef SVAL
#undef IVAL
}


