XCOMM $XConsortium: README.src /main/3 1996/04/23 20:03:43 drk $

 Executable:    abmf

Description:    Motif/CDE code-generator
Revision: dunn: 7 June, 1994

-------------------------------------------------------
-------------------------------------------------------

Module          Prefix          Description
------          ------          -----------------------
Motif-codegen	abmf_          


			  INTRODUCTION

This document has been written primarily to give an overview of how the
code generator (dtcodegen) for the application builder is implemented. 
Its primary thrust is to provide information on how to add support for 
new widgets and object types in the code generator.


			    SYNOPSIS


A few basic principle drive the code generator, and understanding them
should make working on dtcodegen much easier. These principles are explained
in more detail later on, but I'll give a brief synopsis here.

All code generation is driven by the GenCodeInfo data type. A parameter
of this type gets passed in to many functions in the code generator and
is used to modify the way code is generated. This structure holds data that
has a rather wide affect, such as what resources to put in the code file, what
resources to put in the resource file, what form of internationalization is
being used, and whether or not a function is currently being written. If
a function is being written, this data type determines what type of function
is being generated, what the parameters to the function are, what object
is being created by the function, and the like. Be sure to keep this 
data up-to-date at all times, especially if you are generating functions
other than library functions.

abmfP_write_create_widgets_for_comp_obj() is guaranteed to be called
for every composite object being written. This is the first place to
look when implementing a new object type. Modifications to handle the
new object type should be put in this function or in
abmfP_write_create_widgets_for_one_obj().

Always use abmfP_parent() to get the parent of a widget. Some objects are
ignored because they are only used by the front end, and abmfP_parent()
will skip past them.

Use abmfP_get_c_name() to get the C identifier for an object. This takes
a GenCodeInfo, and will automatically give back instance pointers or
global references, as needed.

A struct obj is an object that defines a C struct. In other words, a
C struct is written for each window in the project, so each window is
a struct obj. Substruct objs define substructures (e.g., menus).

instances.c should contain ALL widget-creation code. Do not put code
to write widget creation anywhere else, because it becomes very difficult
to track down problems.

args.c should contain ALL resource-handling code. This model supports
"classes" of resources that allow some resources to be written out in
one way, and others at a different time. If all else fails, args.c functions
exist to write out individual resource values.

"dump" vs. "write" vs. "spew": The identifiers in dtcodegen that deal
with output files, and resource files in particular, use these three
terms. Data is "dumped" to a resource file, "written" to the C code file,
and "spewed" data can go to either place, depending upon context. For
instance a spewed resource will go to either the resource or code file,
depending on the user's options. The "spew" functions should be used
most often, because they handle a lot of details.

abio_printf(), abio_puts(), abio_indent(), abio_outdent() and related
functions should be used to write out C code. STRINGS PASSED TO THESE
FUNCTIONS SHOULD *NOT* CONTAIN NEWLINES, EXCEPT AT THE BEGINNING OR
END OF THE STRING TO BE PRINTED.



			GenCodeInfo STRUCT

Here's the structure:

typedef struct
{
    /* write arg = write to C file
     * dump arg = dump to resource file
     */
    File		code_file;		/* C code */
    File		resource_file;		/* dumped resources */
    BOOL		prototype_funcs;	/* write prototypes? */
    BOOL		dump_resources_i18n;	/* dump i18n res's */
    BOOL		dump_resources_all;	/* dump all res's */
    ABMF_I18N_METHOD	i18n_method;		/* intl'zation method */
    BOOL		writing_func;	/* currently writing a func? */
    GenFuncInfoRec	cur_func;	/* func currently being generated */
} GenCodeInfoRec, *GenCodeInfo;


The GenFuncInfoRec is too large to be included here, but this data type
determines nearly all aspects of how the code is to be written. It is
passed in to many functions in dtcodegen, which modify their operations
based on the data stored therein.

The data that is used most frequently are the fields code_file and
resource_file, which hold the open streams for the current code and resource
files, respectively.



			    WIDGET CREATION

All widget creation should occur in the file instances.c. It's most useful
public functions are:

	abmfP_write_create_widgets_for_comp_obj()
	abmfP_write_create_widgets_for_one_obj()
	abmfP_write_add_callback()

abmfP_write_create_widgets_for_comp_obj() writes all widgets necessary 
for a composite object, and may or may not call 
abmfP_write_create_widgets_for_one_obj().  It is guaranteed that 
abmfP_write_widgets_for_comp_obj() will be called for the root node of 
every salient ui object in the project. This is the best place to add
a new "type" of object. 

instances.c has a number of private functions to help with widget creation.
The most easily used are write_create_widget_by_xt_va_create(), and
write_create_widget_by_non_va_conv_func(). These handle creating the
widgets and setting their resources. You can also call 
write_comp_create_all_subobjs, which handles the general-purpose case.

The functions that handle composite objects should start with write_comp_,
and those that handle only one object should have names that start with
write_obj_.



	     LOCAL VARIABLES FOR OBJECT-CREATION FUNCTIONS

All local variables for object-creation functions are written by the 
function abmfP_write_create_proc_decls() in create_decls.c. Defined
local variables are carefully kept track of in the GenCodeInfo struct,
so it can be easily determined whether a particular variable exists
in the current function, and whether or not it has a valid value. This
also removes the possibility of defining the same variable twice.



			    Xt RESOURCES

All Xt resources are handled in the file args.c. The functions in this
file will return the number of resources of a particular "class" an object
has, and will write them to the appropriate file, as well as providing
other information about the resources.

The argument "classes" are defined as follows:

	ABMF_ARGCLASS_UNDEF
	ABMF_ARGCLASS_NONE
	ABMF_ARGCLASS_TYPED
	ABMF_ARGCLASS_WIDGET_REF
	ABMF_ARGCLASS_OTHER
	ABMF_ARGCLASS_ALL                /* composite class */
	ABMF_ARGCLASS_ALL_BUT_WIDGET_REF /* composite class */

	abmfP_get_num_code_file_args_of_classes()
	abmfP_get_num_res_file_args_of_classes()
	abmfP_get_args_of_classes()

The functions that write arguments and argument lists also take
an argument class parameter. They also take a parameter that determines
the style of argument output. They format type and functions are:

        ABMF_ARGFMT_ARRAY
	ABMF_ARGFMT_VA_LIST

 	abmfP_obj_spew_args()
	abmfP_write_arg_val()


A few utility functions exist to help with writing argument lists:
	
	abmfP_xt_va_list_open()		  /* indent() */
	abmfP_xt_va_list_open_setvalues() /*writes XtVaSetValues(widget,\n"*/
	abmfP_xt_va_list_close()	  /* NULL);\n, outdent() */


Here are more resource (argument) utility functions:

	abmfP_arg_is_dumped()		/* dupmed to resource file */
	abfmP_arg_is_written()		/* written to code file */
	abmfP_arg_is_i18n()		/* i18n-related */
	abmfP_get_res_type(arg, res);	/* gets AB_ARG_TYPE for resource */



			"LIBRARY" FUNCTIONS

"Library" functions are those general-purpose functions that are put
in the user's application. An example is the dtb_create_greyed_pixmap()
function.

LibFuncRec is the data type that is used to define a library function,
and contains the function's declaration (prototype) and definition.

More needs to be written on this, but I don't have time, right now...



			GENERATED STRUCTURES

Generated data types consist primarily of structures that define
the user-interface elements of the project. A "struct obj" is an object
that has a structure defined to represent it that is used for a global
variable. A "substruct obj" has a structure defined for it that exists
only inside another structure. For instance, a window is a struct obj and
has a global structure and variable created to define it. A menu  is
a substruct obj because the structure defined for it is only used inside
of other structures.

	abmfP_obj_has_field()		/* a field exists for obj */
	abmfP_obj_has_struct_field()	/* a struct field exists for obj */
	abmfP_obj_has_substruct_field()	/* a substructe field exists for obj */
	abmfP_obj_is_struct_obj()	/* obj is root of struct */
	abmfP_obj_is_substruct_obj()	/* obj is root of substructure */



			OBJECT/IDENTIFIER NAMES

There are several types of "names" for an object. One is the "C" identifier,
which is a reference to a C variable. This variable can be accessed via
a local instance pointer, or through the global variable. It is also
necessary to be able to get the name of the structure type an object is
in and also the name of the widget that the object causes to be generated.

The functions that don't specify a scope (e.g., abmfP_get_c_name(), vs.
abmfP_get_c_global_name()) determine the best scope from the GenCodeInfo
data and should be used whenever possible.


- These get the name of the variable for this object
    abmfP_get_c_name()		- "appropriate" name, given genCodeInfO
    abmfP_get_c_name_global()	- global variable name
    abmfp_get_c_name_in_inst()	- relative to instance->
    abmfP_get_c_name_in_subinst() - relative to instance->substruct.

- These get the name of the widget for this object
    abmfP_get_widget_name()
    abmfP_get_widgt_global_name()

- These get the name of the structure variable this obj belongs to,
- or the type name of the structure.
    abmfP_get_c_struct_ptr_type_name()
    abmfP_get_c_struct_global_name()
    abmfP_get_c_struct_name()



			OUTPUTTING C CODE

abio_printf() and related functions should be used to actually write
out anything to the C (code) file. Strings to these functions should
never contain a newline, except at the beginning or end of the string
to be printed. These functions look for newlines in order to automatically
indent their output.

abio_indent() and abio_outdent() should be used to change the indent
level in the output C file. By doing this, called functions can automatically
indent properly, regardless of context.

Several functions can be used to declare and write C functions. The _decl()
functions write the function prototypes, and the _begin() functions write
the beginning of the function, including the name, parameters and opening
curly brace. Some of them take variable argument lists, which allow 
arbitrary parameters to be written into the declarations or functions.
These also handle keeping the GenCodeInfo data up-to-date. Some of these
functions are:

    abmfP_write_c_block_begin()
    abmfP_write_c_block_end()
    abmfP_write_c_comment()
    abmfP_write_c_include()
    abmfP_write_c_func_decl()
    abmfP_write_c_func_begin()
    abmfP_write_c_func_end()
    abmfP_write_xm_callback_decl()
    abmfP_write_xm_callback_begin()
    abmfP_write_xm_callback_end()



			GENERAL UTILITIES

abmfP_parent() gets the parent of an object, and should always be used
to get object parents. This is because some objects are ignored completely
when generating code, and this function will skip those objects.

ObjWClassIs(), ObjWClassIsLabel(), ObjWClassIsShell(), ... These functions
return BOOL and check the class_name of the object directly.

