308 lines
12 KiB
Plaintext
308 lines
12 KiB
Plaintext
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.
|
|
|