Files
cdesktop/cde/programs/dtappbuilder/src/abmf/abmf.c
Lev Kujawski a6ea2a2d52 Centralize catgets() calls through MsgCat
CDE has relied upon catgets() implementations following a relaxed
interpretation of the XPG internationalization standard that ignored
-1, the standard error value returned by catopen, as the catalog
argument. However, this same behavior causes segmentation faults with
the musl C library.

This patch:

- Centralizes (with the exception of ToolTalk) all calls to catopen(),
  catgets(), and catclose() through MsgCat within the DtSvc library.
- Prevents calls to catgets() and catclose() that rely upon
  undefined behavior.
- Eliminates a number of bespoke catgets() wrappers, including multiple
  redundant caching implementations designed to work around a design
  peculiarity in HP/UX.
- Eases building CDE without XPG internationalization support by providing
  the appropriate macros.
2021-06-02 19:55:15 -06:00

2253 lines
55 KiB
C

/*
* 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: abmf.c /main/6 1996/11/21 12:31:02 mustafa $
*
* @(#)abmf.c 3.53 16 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.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/times.h>
#include <time.h>
#include <limits.h>
#include <ctype.h>
#include <Dt/MsgCatP.h>
#include <ab_private/util.h>
#include <ab_private/obj.h>
#include <ab_private/objxm.h>
#include <ab_private/bil.h>
#include <ab_private/dtb_utils.h>
#include "write_codeP.h"
#include "motifdefsP.h"
#include "argsP.h"
#include "lib_func_stringsP.h"
#include "instancesP.h"
#include "ui_header_fileP.h"
#include "abmfP.h"
#include <ab_private/abmf.h>
/* glibc considers CLK_TCK obsolete */
#if defined(__linux__) && !defined(CLK_TCK)
#define CLK_TCK CLOCKS_PER_SEC
#endif
#ifdef __cplusplus
extern "C" {
#endif
extern long _sysconf(int name); /* CLK_TCK uses this */
#ifdef __cplusplus
} // extern "C"
#endif
typedef enum
{
ABMF_PROFILE_UNDEF = 0,
ABMF_PROFILE_LOAD,
ABMF_PROFILE_CONFIG,
ABMF_PROFILE_TRAVERSALS,
ABMF_PROFILE_WHAT_NUM_VALUES
} ABMF_PROFILE_WHAT;
typedef struct
{
BOOL force_load_all;
ABMF_PROFILE_WHAT debug_profile_what;
ABMF_CGEN_RESTRICTION cgen_restriction;
BOOL dump_tree;
StringList files;
BOOL i18n;
BOOL write_main;
BOOL show_all_windows;
BOOL show_all_windows_set;
BOOL merge_files;
ISTRING proj_file;
BOOL prototype_funcs;
BOOL source_browser;
BOOL use_default_project;
int verbosity;
BOOL write_all_resources;
BOOL write_i18n_resources;
} CmdlineArgsRec, *CmdlineArgs;
BOOL freshenUnchangedFiles = TRUE;
/*
* Private Functions
*/
static int abmf_init(void);
static int abmf_usage(void);
static int parse_args(int argc, char *argv[], CmdlineArgs args);
static int find_proj_file(CmdlineArgs args);
static int mark_modules_to_load_and_write(
ABObj project,
BOOL loadAllModules,
BOOL genAllModules,
BOOL genNoModules,
StringList fileNames
);
static int load_marked_modules(ABObj project);
static int load_module(ABObj module);
static BOOL write_required(ABObj tree);
static int examine_tree(ABObj project);
static int munge_ensure_win_parent(ABObj win);
static int munge_liberate_menu(ABObj menu);
static int dup_all_menu_refs(ABObj project);
static int abmfP_dup_menu_ref_tree(ABObj obj);
static int abmfP_do_dup_menu_ref_tree(ABObj obj);
static int dump_tree(ABObj tree);
static int print_tree(ABObj root, int indent);
static int abmfP_prepare_tree(ABObj project);
static int abmfP_create_obj_data_for_project(ABObj project);
static int abmfP_create_obj_data_for_module(ABObj objInModule);
static int ensure_data_for_module_obj(ABObj module);
static BOOL proj_file_has_modules(
STRING projFileName,
StringList fileNames
);
static int replace_string_shorter(
STRING buf,
STRING subStr,
STRING replaceStr
);
/*
* Debugging routines
*/
#ifdef DEBUG
static int dump_callbacks(ABObj project);
static int debug_verify_tree(ABObj root);
#endif /* DEBUG */
#ifdef DEBUG /* performance testing */
static int time_traversal(ABObj root);
static int get_cur_time(double *realTimeOut, double *cpuTimeOut);
#endif /* DEBUG */
/* Internationalization defines */
nl_catd Dtb_project_catd;
/* Workaround for XPG4 API compatibility */
#if !defined(NL_CAT_LOCALE)
#define NL_CAT_LOCALE 0
#endif
/* ARGSUSED */
int
main(int argc, STRING *argv)
{
int exitValue = 0;
int iRC= 0; /* int return code */
CmdlineArgsRec cmdlineRec;
CmdlineArgs cmdline = &cmdlineRec;
ABObj project = NULL;
ABObj module = NULL;
int num_modules_processed = 0;
BOOL genAllFiles = FALSE;
BOOL genMain = FALSE;
BOOL genMainOnly = FALSE;
BOOL useDefaultProject = FALSE;
BOOL showAllWindows = FALSE;
STRING errmsg = NULL;
#ifdef DEBUG /* performance testing */
double progStartSeconds = 0.0;
double progEndSeconds = 0.0;
double progSeconds = 0.0;
double progStartCPUSeconds = 0.0;
double progEndCPUSeconds = 0.0;
double progCPUSeconds = 0.0;
double configStartSeconds = 0.0;
double configEndSeconds = 0.0;
double configSeconds = 0.0;
double configStartCPUSeconds = 0.0;
double configEndCPUSeconds = 0.0;
double configCPUSeconds = 0.0;
double loadStartSeconds = 0.0;
double loadEndSeconds = 0.0;
double loadSeconds = 0.0;
double loadStartCPUSeconds = 0.0;
double loadEndCPUSeconds = 0.0;
double loadCPUSeconds = 0.0;
double startupStartSeconds = 0.0;
double startupEndSeconds = 0.0;
double startupSeconds = 0.0;
double startupStartCPUSeconds = 0.0;
double startupEndCPUSeconds = 0.0;
double startupCPUSeconds = 0.0;
get_cur_time(&progStartSeconds, &progStartCPUSeconds);
startupStartSeconds = loadStartSeconds = configStartSeconds
= progStartSeconds;
startupStartCPUSeconds = loadStartCPUSeconds = configStartCPUSeconds
= progStartCPUSeconds;
#endif /* DEBUG */
/*
* Open the standard message catalog for the project.
*/
Dtb_project_catd = CATOPEN("dtcodegen", NL_CAT_LOCALE);
if (Dtb_project_catd == (nl_catd)-1)
{
fprintf(stderr,
"WARNING: Could not open message catalog: dtcodegen.cat\n");
}
util_init(&argc, &argv);
dtb_save_command(argv[0]);
objxm_init(NULL);
abmf_init();
if ((iRC = parse_args(argc, argv, cmdline)) < 0)
{
exit(1);
}
util_set_verbosity(cmdline->verbosity);
/*********************************************************************
** **
** Figure out what the user wants **
** **
*********************************************************************/
/*
* Find the project file
*/
if (cmdline->use_default_project)
{
useDefaultProject = TRUE;
}
else if (cmdline->proj_file == NULL)
{
int numProjFiles = find_proj_file(cmdline);
if (cmdline->proj_file == NULL)
{
if (!strlist_is_empty(cmdline->files))
{
useDefaultProject = TRUE;
if (!util_be_silent())
{
util_printf(
CATGETS(Dtb_project_catd, 1, 1,
"No project file that references module(s) - using defaults\n"));
}
}
else if (numProjFiles == 0)
{
util_printf(
CATGETS(Dtb_project_catd, 1, 2,
"No files specified, and no project file found\n"));
abmf_usage();
}
else
{
/* assume find_proj_file() complained sufficiently */
exit(1);
}
}
}
genMain = FALSE;
genMainOnly = FALSE;
genAllFiles = FALSE;
if (strlist_is_empty(cmdline->files))
{
if (cmdline->write_main)
{
/* only -main was specified */
genMain = TRUE;
genMainOnly = TRUE;
}
else
{
/* no specific files requested - gen them all */
genAllFiles = TRUE;
genMain = TRUE;
}
}
else
{
/* files specified */
if (cmdline->write_main)
{
genMain = TRUE;
if (useDefaultProject)
{
/* dtcodegen -np module.bil -main : only gen main */
genMainOnly = TRUE;
}
}
else
{
if (useDefaultProject)
{
genAllFiles = TRUE;
genMain = TRUE;
}
}
}
if (cmdline->show_all_windows_set)
{
showAllWindows = cmdline->show_all_windows;
}
else if (useDefaultProject)
{
/* user did not override, so we're going to set show_all_windows */
showAllWindows = TRUE;
}
util_dprintf(1, "main:%d mainonly:%d all:%d defaultproj:%d showall:%d\n",
genMain, genMainOnly, genAllFiles, useDefaultProject, showAllWindows);
if ((!util_be_silent()) && (cmdline->proj_file != NULL))
{
char *proj_file_name = istr_string_safe(cmdline->proj_file);
util_printf(
CATGETS(Dtb_project_catd, 1, 3, "Reading project %s.\n"),
proj_file_name);
}
#ifdef DEBUG /* performance testing */
get_cur_time(&loadStartSeconds, &loadStartCPUSeconds);
#endif
/*********************************************************************
** **
** Load or create the project **
** **
*********************************************************************/
if (cmdline->proj_file != NULL)
{
/* project = bil_load_file(istr_string(cmdline->proj_file), NULL, project);
assert(project != NULL); */
iRC = bil_load_file_and_resolve_all(
istr_string(cmdline->proj_file), NULL, &project);
if (iRC < 0)
{
exitValue = 1;
goto epilogue;
}
}
if (useDefaultProject)
{
int i = 0;
int numModuleFiles = 0;
STRING moduleFileName = NULL;
ABObj fileObj = NULL;
char *dotPtr = NULL;
char projNameBuf[1024];
*projNameBuf = 0;
/*
* Create the default project
*/
if (project != NULL)
{
ABObj oldProject = project;
project = obj_create(AB_TYPE_PROJECT, NULL);
obj_move_children(project, oldProject);
obj_destroy(oldProject);
}
else
{
project = obj_create(AB_TYPE_PROJECT, NULL);
}
util_strncpy(projNameBuf,
strlist_get_str(cmdline->files, 0, NULL), 1024);
dotPtr = strrchr(projNameBuf, '.');
if (dotPtr != NULL)
{
*dotPtr = 0;
}
obj_set_name(project, projNameBuf);
obj_set_file(project, strlist_get_str(cmdline->files, 0, NULL));
obj_set_is_default(project, TRUE);
/*
* Create "files" to get converted to undefined modules
*/
numModuleFiles = strlist_get_num_strs(cmdline->files);
for (i = 0; i < numModuleFiles; ++i)
{
moduleFileName = strlist_get_str(cmdline->files, i, NULL);
fileObj = obj_create(AB_TYPE_FILE, project);
obj_set_file(fileObj, moduleFileName);
}
}
/*
* Load the appropriate files
*/
if (genMain)
{
mfobj_set_flags(project, CGenFlagLoadMe|CGenFlagIsReferenced);
obj_set_write_me(project, TRUE);
}
mark_modules_to_load_and_write(
project, cmdline->force_load_all, genAllFiles, genMainOnly, cmdline->files);
load_marked_modules(project);
#ifdef DEBUG /* performance testing */
get_cur_time(&loadEndSeconds, &loadEndCPUSeconds);
loadSeconds = loadEndSeconds - loadStartSeconds;
loadCPUSeconds = loadEndCPUSeconds - loadStartCPUSeconds;
printf("load real:%lg CPU:%lg\n", loadSeconds, loadCPUSeconds);
#endif /* DEBUG */
if (iRC < 0)
{
char *prog_name_string = util_get_program_name();
fprintf(stderr,
CATGETS(Dtb_project_catd, 1, 4,
"%s: exiting due to error loading project.\n"),
prog_name_string);
exit(1);
}
if (cmdline->debug_profile_what == ABMF_PROFILE_LOAD)
{
exit(0);
}
/*
* See if we actually have anything to write
*/
if (!write_required(project))
{
char *prog_name_string = util_get_program_name();
fprintf(stderr,
CATGETS(Dtb_project_catd, 1, 5,
"%s: Nothing to do!\n"), prog_name_string);
exit(1);
}
/*
* Configure the raw objects into AB objects
*/
if (showAllWindows)
{
ABObj window = NULL;
AB_TRAVERSAL trav;
for (trav_open(&trav, project, AB_TRAV_WINDOWS);
(window = trav_next(&trav)) != NULL; )
{
obj_set_is_initially_visible(window, TRUE);
}
trav_close(&trav);
}
#ifdef DEBUG /* performance testing */
get_cur_time(&configStartSeconds, &configStartCPUSeconds);
#endif
examine_tree(project);
#ifdef DEBUG /* performance testing */
get_cur_time(&configEndSeconds, &configEndCPUSeconds);
configSeconds = configEndSeconds - configStartSeconds;
configCPUSeconds = configEndCPUSeconds - configStartCPUSeconds;
get_cur_time(&startupEndSeconds, &startupEndCPUSeconds);
startupSeconds = startupEndSeconds - startupStartSeconds;
startupCPUSeconds = startupEndCPUSeconds - startupStartCPUSeconds;
/*
* Print out startup stats (if debugging build)
*/
util_printf("Startup real time: %lg s (%lg s load, %lg s config)\n",
startupSeconds, loadSeconds, configSeconds);
util_printf("Startup CPU time: %lg s (%lg s load, %lg s config)\n",
startupCPUSeconds, loadCPUSeconds, configCPUSeconds);
#endif /* DEBUG */
#ifdef DEBUG
util_dprintf(1, "after configure_tree\n");
debug_verify_tree(project);
#endif /* DEBUG */
/*
* The tree has been loaded, examined, mangled, and generally messed with.
* Now, do what the user has requested.
*/
#ifdef DEBUG
/* make sure we didn't muss anything up */
if (debugging())
{
int numObjs = trav_count(project, AB_TRAV_ALL);
obj_tree_verify(project);
if ( ((debug_level() >= 10) || ((25*debug_level()) >= numObjs))
&& (!cmdline->dump_tree))
{
objxm_tree_print(project);
}
}
#endif /* DEBUG */
if (cmdline->dump_tree)
{
dump_tree(project);
}
else
{
AB_ARG_CLASS_FLAGS dumpedRes = obj_get_res_file_arg_classes(project);
ABMF_I18N_METHOD i18n_method = ABMF_I18N_NONE;
if (obj_get_i18n_enabled(project))
i18n_method = ABMF_I18N_XPG4_API;
/*
* Generate the code!
*/
iRC = abmf_generate_code(
project,
cmdline->cgen_restriction,
cmdline->merge_files,
i18n_method,
cmdline->prototype_funcs,
dumpedRes
);
if (iRC < 0)
{
exitValue = 1;
}
}
#ifdef DEBUG /* performance testing */
get_cur_time(&progEndSeconds, &progEndCPUSeconds);
progSeconds = progEndSeconds - progStartSeconds;
progCPUSeconds = progEndCPUSeconds - progStartCPUSeconds;
util_printf("Total real time: %lg s CPU time: %lg s\n",
progSeconds, progCPUSeconds);
#endif /* DEBUG */
epilogue:
#ifdef DEBUG
debug_verify_tree(project);
#endif /* DEBUG */
return exitValue;
}
static int
parse_args(int argc, char *argv[], CmdlineArgs cmdline)
{
int iReturn = 0;
int argCount = 0;
/*
* Set default values
*/
cmdline->force_load_all = TRUE;
cmdline->debug_profile_what = ABMF_PROFILE_UNDEF;
cmdline->cgen_restriction = ABMF_CGEN_ALL;
cmdline->dump_tree = FALSE;
cmdline->files = strlist_create();
cmdline->i18n = FALSE;
cmdline->show_all_windows = FALSE;
cmdline->show_all_windows_set = FALSE;
cmdline->write_main = FALSE;
cmdline->merge_files = TRUE;
cmdline->proj_file = NULL;
cmdline->prototype_funcs = TRUE;
cmdline->source_browser = FALSE;
cmdline->use_default_project = FALSE;
cmdline->verbosity = util_get_verbosity();
cmdline->write_all_resources = FALSE;
cmdline->write_i18n_resources = FALSE;
for (argCount = 1; argCount < argc; ++argCount)
{
char *arg = argv[argCount];
if (*arg == '-')
{
if (strcmp(arg, "-s") == 0 ||
strcmp(arg, "-silent") == 0)
{
cmdline->verbosity = 0;
}
else if (strcmp(arg, "-a") == 0 ||
strcmp(arg, "-ansi") == 0)
{
cmdline->prototype_funcs = TRUE;
}
else if (util_streq(arg, "-freshen"))
{
freshenUnchangedFiles = TRUE;
}
else if (util_streq(arg, "-nofreshen"))
{
freshenUnchangedFiles = FALSE;
}
#ifdef DEBUG
else if (util_streq(arg, "-tree"))
{
cmdline->dump_tree = TRUE;
}
#endif /* DEBUG */
else if (util_streq(arg, "-changed"))
{
cmdline->cgen_restriction = ABMF_CGEN_BY_DATE;
}
else if (strcmp(arg, "-k") == 0 ||
strcmp(arg, "-kandr") == 0)
{
cmdline->prototype_funcs = FALSE;
}
else if (strcmp(arg, "-main") == 0)
{
cmdline->write_main = TRUE;
}
else if (util_streq(arg, "-showall"))
{
cmdline->show_all_windows = TRUE;
cmdline->show_all_windows_set = TRUE;
}
else if (util_streq(arg, "-noshowall"))
{
cmdline->show_all_windows = FALSE;
cmdline->show_all_windows_set = TRUE;
}
else if (util_streq(arg, "-merge"))
{
cmdline->merge_files = TRUE;
}
else if (util_streq(arg, "-nomerge"))
{
cmdline->merge_files = FALSE;
}
else if (strcmp(arg, "-P") == 0 ||
strcmp(arg, "-p") == 0 ||
strcmp(arg, "-project") == 0)
{
if ((argCount + 1) >= argc)
{
util_error( CATGETS(Dtb_project_catd, 1, 6,
"Missing project name for -p option"));
abmf_usage();
}
else
{
/*
* get the project file name
*/
STRING projArg;
++argCount;
projArg= argv[argCount];
if ( util_file_name_has_extension(projArg, "bip")
|| util_file_name_has_extension(projArg, "bix"))
{
cmdline->proj_file = istr_const(projArg);
}
else
{
char projFile[MAX_PATH_SIZE];
sprintf(projFile, "%s.bip", projArg);
if (!util_file_exists(projFile))
{
char encapsFile[MAXPATHLEN];
sprintf(encapsFile, "%s.bix", projArg);
if (util_file_exists(encapsFile))
{
strcpy(projFile, encapsFile);
}
}
cmdline->proj_file = istr_create(projFile);
}
}
}
else if ( util_streq(arg, "-np")
|| util_streq(arg, "-noproject"))
{
cmdline->use_default_project = TRUE;
}
else if (strcmp(arg, "-help") == 0)
{
abmf_usage();
}
else if (strcmp(arg, "-i") == 0 ||
strcmp(arg, "-i18n") == 0)
{
cmdline->i18n = TRUE;
}
else if (strcmp(arg, "-r") == 0 ||
strcmp(arg, "-resources") == 0)
{
cmdline->write_all_resources = TRUE;
}
else if (strcmp(arg, "-sb") == 0)
{
cmdline->source_browser = TRUE;
}
else if (strncmp(arg, "-v", 2) == 0)
{
cmdline->verbosity = 2;
}
/*
* debugging options
*/
#ifdef DEBUG
else if (strncmp(arg, "-V", 2) == 0)
{
int i;
for (i = 1; arg[i] == 'V'; ++i)
{ /* empty */ }
--i;
cmdline->verbosity = i;
}
else if (strncmp(arg, "-time", 5) == 0)
{
if (argCount < (argc-1))
{
arg = argv[++argCount];
if (util_streq(arg, "load"))
{
cmdline->debug_profile_what = ABMF_PROFILE_LOAD;
}
}
}
else if (strncmp(arg, "-loadall", 8) == 0)
{
cmdline->force_load_all = TRUE;
}
#endif /* DEBUG */
else
{
char *prog_name_string = util_get_program_name();
fprintf(stderr, CATGETS(Dtb_project_catd, 1, 7,
"%s: Illegal option \"%s\"\n\n"), prog_name_string, arg);
abmf_usage();
}
} /* arg == '-' */
else
{
/*
* It's a file name
*/
if ( util_file_name_has_extension(arg, "bip")
|| util_file_name_has_extension(arg, "bix") )
{
if (cmdline->proj_file != NULL)
{
util_error(
CATGETS(Dtb_project_catd, 1, 8,
"Only one project file may be specified."));
abmf_usage();
}
else
{
cmdline->proj_file = istr_const(arg);
}
}
else
{
ISTRING newFile = NULL;
if (util_file_name_has_ab_extension(arg))
{
newFile = istr_const(arg);
}
else
{
char fileName[MAX_PATH_SIZE];
snprintf(fileName, sizeof(fileName), "%s.bil", arg);
newFile = istr_create(fileName);
}
strlist_add_istr(cmdline->files, newFile, NULL);
} /* not project file */
} /* ! flag arg */
} /* for argCount */
/*
* Make the comand-line args consistent
*/
if (cmdline->use_default_project && (cmdline->proj_file != NULL))
{
char *proj_file_name = istr_string_safe(cmdline->proj_file);
util_printf_err(
CATGETS(Dtb_project_catd, 1, 9,
"ignoring -noproject (-np) because project file was specified: %s\n"),
proj_file_name);
cmdline->use_default_project = FALSE;
}
return iReturn;
}
static int
mark_modules_to_load_and_write(
ABObj project,
BOOL loadAllModules,
BOOL genAllModules,
BOOL genNoModules,
StringList fileNames
)
{
int return_value = 0;
AB_TRAVERSAL fileTrav;
ABObj file = NULL;
ISTRING fileName = NULL;
char newModuleName[1024];
STRING dotPtr = NULL;
AB_TRAVERSAL allTrav;
ABObj obj = NULL;
ABObj obj1 = NULL;
ABObj obj2 = NULL;
AB_TRAVERSAL moduleTrav;
ABObj module = NULL;
ABObj winParent = NULL;
*newModuleName = 0;
/*
* Convert remaining files into undefined modules
*/
for (trav_open(&fileTrav, project, AB_TRAV_FILES | AB_TRAV_MOD_SAFE);
(file = trav_next(&fileTrav)) != NULL; )
{
fileName = istr_create(obj_get_file(file));
util_get_file_name_from_path(
istr_string(fileName), newModuleName, 1024);
dotPtr = strrchr(newModuleName, '.');
if (dotPtr != NULL)
{
*dotPtr = 0;
}
module = obj_find_module_by_name(project, newModuleName);
if (module != NULL)
{
/* this module already exists, probably because of a forward */
/* reference */
obj_destroy(file);
}
else
{
obj_set_type(file, AB_TYPE_MODULE);
module = file; file = NULL;
obj_set_name(module, newModuleName);
obj_set_is_defined(module, FALSE);
mfobj_set_flags(module, CGenFlagLoadMe|CGenFlagIsReferenced);
}
/*
* Objects/modules created as a forward reference will
* not have their file names set, so we're going to
* check it.
*/
if (obj_get_file(module) == NULL)
{
obj_set_file(module, istr_string(fileName));
}
istr_destroy(fileName);
load_module(module);
}
trav_close(&fileTrav);
/*
* Mark the modules that are to be written
*/
{
char explodedModuleFile[MAXPATHLEN+1];
*explodedModuleFile = 0;
for (trav_open(&moduleTrav, project, AB_TRAV_MODULES|AB_TRAV_MOD_SAFE);
(module = trav_next(&moduleTrav)) != NULL; )
{
sprintf(explodedModuleFile, "%s.bil", obj_get_name(module));
if ((genAllModules && obj_is_defined(module)) ||
(strlist_str_exists(fileNames, explodedModuleFile) && (!genNoModules)))
{
if (obj_is_defined(module)) /* must be defined!! */
{
strlist_set_str_data(fileNames, explodedModuleFile, (void*)TRUE);
obj_set_write_me(module, TRUE);
}
}
}
trav_close(&moduleTrav);
}
/*
* Make sure all the modules on the command line were found
*/
{
int i = 0;
int numFiles = strlist_get_num_strs(fileNames);
STRING fileName = NULL;
BOOL wasFound = FALSE;
void *wasFoundVoidPtr;
BOOL errOccurred = FALSE;
for (i = 0; i < numFiles; ++i)
{
fileName = strlist_get_str(fileNames, i, &wasFoundVoidPtr);
assert(fileName != NULL);
wasFound = (BOOL)(unsigned long)wasFoundVoidPtr;
if (!wasFound)
{
util_printf_err("module not found in project: %s\n", fileName);
errOccurred = TRUE;
}
}
if (errOccurred)
{
exit(1);
}
}
/*
* Determine dependencies necessary to write the requested modules
*/
/* if loadAll... */
{
for (trav_open(&allTrav, project, AB_TRAV_ALL | AB_TRAV_MOD_SAFE);
(obj = trav_next(&allTrav)) != NULL; )
{
switch (obj_get_type(obj))
{
case AB_TYPE_MODULE:
if (obj_get_write_me(obj))
{
mfobj_set_flags(obj, CGenFlagIsReferenced);
}
break;
/*
* win-parent can be in another module
*/
case AB_TYPE_DIALOG:
case AB_TYPE_BASE_WINDOW:
if ( obj_is_defined(obj)
&& obj_is_popup(obj)
&& obj_get_write_me(obj_get_module(obj)))
{
if ((winParent = obj_get_win_parent(obj)) != NULL)
{
mfobj_set_flags(obj_get_module(winParent),
CGenFlagIsReferenced);
}
}
/* visible windows must be loaded to write main */
if ( obj_get_write_me(project)
&& obj_is_defined(obj) && obj_is_initially_visible(obj))
{
mfobj_set_flags(obj_get_module(obj),
CGenFlagIsReferenced);
}
break;
/*
*
*/
case AB_TYPE_ACTION:
obj1 = obj_get_from(obj);
if (obj_is_project(obj1))
break;
obj2 = obj_get_to(obj);
if ( ( (obj1 != NULL)
&& obj_is_defined(obj1)
&& obj_get_write_me(obj_get_module(obj1)))
||( (obj2 != NULL)
&& obj_is_defined(obj2)
&& obj_get_write_me(obj_get_module(obj2)))
)
{
/*
* At least one object will be written, make sure
* both have data.
*/
if (obj1 != NULL)
{
mfobj_set_flags((obj_get_module(obj1)),
CGenFlagIsReferenced);
}
if (obj2 != NULL)
{
mfobj_set_flags((obj_get_module(obj2)),
CGenFlagIsReferenced);
}
}
/*
* to/from of cross-module conns must be available to write
* main
*/
if ( obj_get_write_me(project)
&& obj_is_defined(obj)
&& obj_is_cross_module(obj))
{
if ((obj1 != NULL) && obj_is_defined(obj1))
{
mfobj_set_flags((obj_get_module(obj1)),
CGenFlagIsReferenced);
}
if ((obj2 != NULL) && obj_is_defined(obj2))
{
mfobj_set_flags((obj_get_module(obj2)),
CGenFlagIsReferenced);
}
}
break;
}
}
trav_close(&allTrav);
}
return 0;
}
static int
load_marked_modules(ABObj project)
{
ABObj module = NULL;
AB_TRAVERSAL moduleTrav;
char fileName[MAXPATHLEN+1] = "";
for (trav_open(&moduleTrav, project, AB_TRAV_MODULES|AB_TRAV_MOD_SAFE);
(module = trav_next(&moduleTrav)) != NULL; )
{
if ( mfobj_has_flags(module, CGenFlagLoadMe)
&& (!obj_is_defined(module)))
{
load_module(module);
}
}
trav_close(&moduleTrav);
return 0;
}
static int
load_module(ABObj module)
{
char fileName[MAXPATHLEN+1];
ABObj newProject = NULL;
ABObj project = obj_get_project(module);
*fileName = 0;
if (obj_get_file(module) != NULL)
{
snprintf(fileName, sizeof(fileName), "%s", obj_get_file(module));
}
else
{
snprintf(fileName, sizeof(fileName), "%s", obj_get_name(module));
if (!util_file_name_has_ab_extension(fileName))
{
strcat(fileName, ".bil");
}
}
newProject = bil_load_file(fileName, NULL, project, NULL);
if (newProject == NULL)
{
/* a failure ocurred. The error has already been reported */
exit(1);
}
else if (newProject != project)
{
util_printf_err(
CATGETS(Dtb_project_catd, 1, 10,
"Unexpected project in file %s. Aborting\n"), fileName);
exit(1);
}
if (!obj_is_defined(module))
{
char *module_name_string = obj_get_name(module);
util_printf_err(
CATGETS(Dtb_project_catd, 1, 11,
"Module %s not found in file %s. Aborting\n"),
module_name_string, fileName);
exit(1);
}
return 0;
}
/*
* Print usage message
*/
static int
abmf_usage(void)
{
char *program_name_string = util_get_program_name();
fprintf(stderr,"\n");
fprintf(stderr,
CATGETS(Dtb_project_catd, 1, 12,
"Usage: %s [options] [project-file] [module-file [module-file] ...]\n\n"),
program_name_string);
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 13,
"Code is generated for each module specified on the command line, or for\n"));
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 14,
"all modules in the project, if no modules are specified. If no project\n"));
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 15,
"file is specified, a project file containing the specified module(s) is\n"));
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 16,
"searched for in the current directory.\n\n"));
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 17,
"Files with extension .bip are assumend to be BIL project files, files with\n"));
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 18,
".bix extension are assumed to be encapsulated BIL files, and files\n"));
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 19,
"With a .bil extension are assumed to be BIL module files.\n\n"));
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 20,
"Options (* = default, + = default with no project file):\n"));
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 21,
" -help (-h) Print out this help message\n"));
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 22,
" -main Write file containing main()\n"));
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 23,
" -changed Only generate files that have changed\n"));
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 24,
"* -merge Merge generated _stubs.c files with previous version\n"));
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 25,
" -nomerge Don't merge existing and new stubs file\n"));
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 26,
"* -project (-p) Specify a project to generate code for\n"));
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 27,
" -noproject (-np) Use default project settings, ignore project file\n"));
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 28,
"+ -showall Application shows (maps) all windows at startup\n"));
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 29,
"* -noshowall Application shows (maps) only initially-visible windows\n"));
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 30,
" -silent (-s) Silent mode, no messages written\n"));
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 31,
" -verbose (-v) Verbose mode, detailed progress messages\n\n"));
/* "-a (-ansi) Write ANSI C code\n" */
/* "-k (-kandr) Write K&R C code, no function prototypes\n" */
/* "-i (-i18n) Create resource file for I18N\n" */
/* "-r (-resources) Write all resources into a resource file\n" */
exit(1);
return ERR_INTERNAL;
}
/*
* Searches the current directory for a project file
* Sets the cmdline->proj_file member
*
* Returns the total number of project files found
*
*/
static int
find_proj_file(CmdlineArgs cmdline)
{
DIR *dir= NULL;
struct dirent *dirEntry= NULL;
int numProjectFiles = 0;
StringListRec projFiles;
strlist_construct(&projFiles);
dir= opendir(".");
if (dir == NULL)
{
perror(CATGETS(Dtb_project_catd,1,32,"Couldn't open '.'"));
return -1;
}
while ((dirEntry= readdir(dir)) != NULL)
{
if (util_file_name_has_extension(dirEntry->d_name, "bip"))
{
/* found a project file! */
strlist_add_str(&projFiles, dirEntry->d_name, NULL);
}
}
numProjectFiles = strlist_get_num_strs(&projFiles);
if (numProjectFiles > 0)
{
int num_strings = strlist_get_num_strs(&projFiles);
int i = 0;
STRING fileName = NULL;
for (i = 0; i < strlist_get_num_strs(&projFiles); ++i)
{
fileName = strlist_get_str(&projFiles, i, NULL);
if (!proj_file_has_modules(fileName, cmdline->files))
{
strlist_remove_index(&projFiles, i);
--i;
}
}
}
if (strlist_get_num_strs(&projFiles) == 1)
{
cmdline->proj_file = istr_create(strlist_get_str(&projFiles, 0, NULL));
}
else if (strlist_get_num_strs(&projFiles) > 1)
{
int i = 0;
char *prog_name_string = util_get_program_name();
fprintf(stderr, CATGETS(Dtb_project_catd, 1, 33,
"%s: Please specify project file (e.g."), prog_name_string);
for (i = 0; i < strlist_get_num_strs(&projFiles); ++i)
{
fprintf(stderr, ", %s", strlist_get_str(&projFiles, i, NULL));
}
fprintf(stderr, "%s", CATGETS(Dtb_project_catd, 1, 34, ")\n"));
if (!strlist_is_empty(cmdline->files))
{
fprintf(stderr,
CATGETS(Dtb_project_catd, 1, 35,
"%s: More than one project contains specified module(s)\n"),
prog_name_string);
}
}
closedir(dir); dir= NULL;
strlist_destruct(&projFiles);
return numProjectFiles;
}
static BOOL
proj_file_has_modules(STRING projFileName, StringList moduleFileNames)
{
BOOL hasModules = FALSE;
char word[1024] = "";
int modulesFound = 0;
int wordLen = 0;
File file = NULL;
int c = 0;
fpos_t fpos;
int numFiles = strlist_get_num_strs(moduleFileNames);
if (numFiles < 1)
{
return TRUE;
}
file = util_fopen_locked(projFileName, "r");
if (file == NULL)
{
perror(projFileName);
return FALSE;
}
while ((c = fgetc(file)) != EOF)
{
if (c == ':')
{
fgetpos(file, &fpos);
*word = 0;
if ( (fgets(word, 6, file) != NULL)
&& (strncmp(word, "files", 5) == 0))
{
/* :files <file-list> */
BOOL filesDone = FALSE;
while (((c = fgetc(file)) != EOF) && (c != '(')) {}
filesDone = (c == EOF);
while (!filesDone)
{
while (((c = fgetc(file)) != EOF) && isspace(c)) {}
ungetc(c, file);
*word = 0;
wordLen = 0;
while (((c = fgetc(file)) != EOF) && (!isspace(c)))
{
if (c == ')')
{
filesDone = TRUE;
break;
}
word[wordLen++] = c;
word[wordLen] = 0;
}
if (c == EOF)
{
filesDone = TRUE;
}
if (*word != 0)
{
int i = 0;
ISTRING temp_istr = istr_create(word);
for (i = 0; i < numFiles; ++i)
{
if (istr_equal(temp_istr,
strlist_get_istr(moduleFileNames, i, NULL)))
{
++modulesFound;
break;
}
}
istr_destroy(temp_istr);
}
}
}
else if ( (strncmp(word, "modul", 5) == 0)
&& (fgets(word, 2, file) != NULL)
&& (strncmp(word, "e", 1) == 0) )
{
/* :module <module-name */
/* REMIND: we need to have this for .bix files to work! */
}
else
{
fsetpos(file, &fpos);
}
} /* c == ':' */
} /* while c != EOF */
util_fclose(file);
hasModules = (modulesFound >= numFiles);
return hasModules;
}
static BOOL
write_required(ABObj tree)
{
BOOL writeSomething= FALSE;
if (obj_get_write_me(tree))
{
writeSomething= TRUE;
}
else
{
AB_TRAVERSAL trav;
ABObj module= NULL;
for(trav_open(&trav, tree, AB_TRAV_MODULES);
(module= trav_next(&trav)) != NULL; )
{
if (obj_get_write_me(module))
{
writeSomething= TRUE;
break;
}
}
trav_close(&trav);
}
return writeSomething;
}
/*
* Initializes everything in abmf.
*/
static int
abmf_init(void)
{
STRING templateFuncName = NULL;
abmfP_motifdefs_init();
abmfP_ui_header_file_init();
abmfP_args_init();
/*
* Turn "template" library functions into printf format strings
*/
templateFuncName = "dtb_default_dragCB";
replace_string_shorter(abmfP_lib_default_dragCB->proto,
templateFuncName, "%s");
replace_string_shorter(abmfP_lib_default_dragCB->def,
templateFuncName, "%s");
templateFuncName = "dtb_default_dropCB";
replace_string_shorter(abmfP_lib_default_dropCB->proto,
templateFuncName, "%s");
replace_string_shorter(abmfP_lib_default_dropCB->def,
templateFuncName, "%s");
return 0;
}
/*
* Replaces all occurences of substr with replacestr.
* replaceStr *must* be shorter than or the same length as subStr
*/
static int
replace_string_shorter(STRING buf, STRING subStr, STRING replaceStr)
{
int numReplaced = 0;
char *bufPtr = buf;
char *bufEnd = buf + strlen(buf);
int subStrLen = strlen(subStr);
char *subStrPtr = subStr;
int replaceStrLen = strlen(replaceStr);
int replaceDiffLen = subStrLen - replaceStrLen;
assert(strlen(subStr) >= (size_t)strlen(replaceStr));
while ((subStrPtr = strstr(bufPtr, subStr)) != NULL)
{
memmove(subStrPtr+replaceStrLen,
subStrPtr+subStrLen,
((int)(bufEnd - (subStrPtr+subStrLen))) + 1);
strncpy(subStrPtr, replaceStr, replaceStrLen); /* no NULL! */
bufPtr = subStrPtr+replaceStrLen;
bufEnd -= replaceDiffLen;
++numReplaced;
}
return numReplaced;
}
/*
*
*/
static int
examine_tree(ABObj project)
{
int returnValue = 0;
AB_TRAVERSAL moduleTrav;
AB_TRAVERSAL uiTrav;
ABObj module = NULL;
ABObj obj = NULL;
ABObj parent = NULL;
StringList proj_callbacks = NULL;
ABObj callbackScopeObj = NULL;
STRING funcName = NULL;
objxm_obj_configure(project, OBJXM_CONFIG_CODEGEN, TRUE);
for (trav_open(&moduleTrav, project, AB_TRAV_MODULES);
(module = trav_next(&moduleTrav)) != NULL; )
{
if (!mfobj_has_flags(module, CGenFlagIsReferenced))
{
continue;
}
#ifdef DEBUG
if (debugging())
{
char name[256];
util_dprintf(1, "Configuring %s\n",
obj_get_safe_name(module, name, 256));
}
#endif /* DEBUG */
objxm_tree_configure(module, OBJXM_CONFIG_CODEGEN);
dup_all_menu_refs(module); /* this can create new objs */
for (trav_open(&uiTrav, module,
AB_TRAV_UI | AB_TRAV_MOD_PARENTS_FIRST | AB_TRAV_MOD_SAFE);
(obj = trav_next(&uiTrav)) != NULL; )
{
if ( (obj_get_class_name(obj) == NULL)
&& (!obj_has_flag(obj, NoCodeGenFlag)) )
{
#ifdef DEBUG
if (debugging())
{
if (!(obj_is_item(obj) || obj_is_menu(obj) || obj_is_message(obj)))
{
char name[256] = "";
util_dprintf(0,
"WARNING: "
"Object has no class name (NoCodeGenFlag not set): %s\n",
obj_get_safe_name(obj, name, 256));
}
}
#endif /* DEBUG */
};
munge_ensure_win_parent(obj);
munge_liberate_menu(obj);
}
trav_close(&uiTrav);
} /* trav modules */
trav_close(&moduleTrav);
abmfP_prepare_tree(project); /* creates extra data for each obj */
return returnValue;
}
static int
munge_ensure_win_parent(ABObj win)
{
ABObj root_window = abmfP_get_root_window(obj_get_project(win));
if (!obj_is_window(win))
{
return 0;
}
if ((obj_get_win_parent(win) == NULL) && (win != root_window))
{
obj_set_win_parent(win, root_window);
}
return 0;
}
static int
munge_liberate_menu(ABObj menu)
{
if (!obj_is_menu(menu))
{
return -1;
}
{
ABObj compRoot = obj_get_root(menu);
AB_OBJECT_TYPE compType = AB_TYPE_UNDEF;
if (compRoot != NULL)
{
compType = obj_get_type(compRoot);
}
if ( (compRoot != menu)
&& ( (compType == AB_TYPE_ITEM)
|| (compType == AB_TYPE_BUTTON)) )
{
menu->part_of = NULL;
}
}
return 0;
}
static int
dup_all_menu_refs(ABObj project)
{
AB_TRAVERSAL moduleTrav;
AB_TRAVERSAL menuTrav;
ABObj module = NULL;
ABObj menu = NULL;
for (trav_open(&moduleTrav, project, AB_TRAV_MODULES);
(module = trav_next(&moduleTrav)) != NULL; )
{
if (!obj_get_write_me(module))
{
continue;
}
for (trav_open(&menuTrav, module, AB_TRAV_MENUS);
(menu = trav_next(&menuTrav)) != NULL; )
{
if (obj_is_ref(menu))
{
abmfP_dup_menu_ref_tree(menu);
if (obj_is_popup(menu))
{
STRING title = obj_get_menu_title(obj_get_parent(menu));
if (!util_strempty(title))
objxm_create_popup_menu_title(menu, OBJXM_CONFIG_CODEGEN,
title);
}
}
}
trav_close(&menuTrav);
}
trav_close(&moduleTrav);
return 0;
}
static int
abmfP_dup_menu_ref_tree(ABObj obj)
{
int rc = 0; /* return code */
int return_value = 0;
ABObj refObj = NULL;
AB_TRAVERSAL trav;
if (!obj_is_menu_ref(obj))
{
return 0;
}
rc = abmfP_do_dup_menu_ref_tree(obj);
if (rc < 0)
{
return rc;
}
/*
* We can't handle multi-layered references, so we are going to collapse
* any reference lists to only reference the final (actual) object.
*/
for (trav_open(&trav, obj, AB_TRAV_UI);
(obj = trav_next(&trav)) != NULL; )
{
refObj = obj_get_actual_obj(obj);
if (refObj != NULL)
{
while (obj_is_ref(refObj))
{
refObj = obj_get_actual_obj(refObj);
}
obj_cvt_to_ref(obj, refObj);
}
}
trav_close(&trav);
return return_value;
}
static int
abmfP_do_dup_menu_ref_tree(ABObj obj)
{
int return_value = 0;
int rc = 0;
ABObj actualMenu = NULL;
if (!obj_is_menu_ref(obj))
{
return 0;
}
actualMenu = obj_get_actual_obj(obj);
if (actualMenu == NULL)
{
return -1;
}
if (obj_get_num_items(obj) != obj_get_num_items(actualMenu))
{
ABObj dupTree = obj_tree_create_ref(actualMenu);
if (dupTree == NULL)
{
return_value = -1;
goto epilogue;
}
rc = obj_move_children(obj, dupTree);
if (rc < 0)
{
return_value = rc;
}
obj_destroy(dupTree);
{
AB_TRAVERSAL trav;
ABObj descendant = NULL;
for (trav_open(&trav, obj,
AB_TRAV_UI|AB_TRAV_MOD_PARENTS_FIRST|AB_TRAV_MOD_SAFE);
(descendant = trav_next(&trav)) != NULL; )
{
if (descendant == obj)
{
continue;
}
if (obj_is_menu_ref(descendant))
{
abmfP_do_dup_menu_ref_tree(descendant);
}
}
trav_close(&trav);
}
}
epilogue:
return return_value;
}
static int
dump_tree(ABObj tree)
{
int return_value = 0;
int old_verbosity = util_get_verbosity();
switch (old_verbosity)
{
case 0: /* FALLTHROUGH */
case 1: util_set_verbosity(3);
break;
case 2: util_set_verbosity(4);
break;
}
print_tree(tree, 0);
epilogue:
util_set_verbosity(old_verbosity);
return return_value;
}
static int
print_tree(ABObj root, int indent)
{
AB_TRAVERSAL trav;
ABObj child = NULL;
int numPrinted = 0;
int travType = AB_TRAV_SALIENT_CHILDREN;
if (util_get_verbosity() >= 4)
{
travType = AB_TRAV_CHILDREN;
}
if ( (travType == AB_TRAV_CHILDREN)
|| (obj_is_salient(root)) )
{
objxm_print_indented(root, indent, util_get_verbosity());
++numPrinted;
}
if (obj_is_module(root) && (!obj_get_write_me(root)))
{
goto epilogue;
}
for (trav_open(&trav, root, travType);
(child = trav_next(&trav)) != NULL; )
{
numPrinted += print_tree(child, indent+4);
}
trav_close(&trav);
/*
* Look for non-salient children that need their children printed
*/
if (travType == AB_TRAV_SALIENT_CHILDREN)
{
for (trav_open(&trav, root, AB_TRAV_CHILDREN);
(child = trav_next(&trav)) != NULL; )
{
if ((!obj_is_salient(child)) && (obj_get_root(child) != root))
{
numPrinted += print_tree(child, indent);
}
}
}
epilogue:
return numPrinted;
}
#ifdef DEBUG
static int
time_traversal(ABObj root)
{
int return_value = 0;
AB_TRAVERSAL trav;
ABObj obj = NULL;
int i = 0;
double startTime = 0;
double endTime = 0;
double totalTravTime = 0;
double oneTravTime = 0;
int numTravs = 1000;
struct tms timeBuf;
long ticks_per_second = sysconf(_SC_CLK_TCK);
int oldVerbosity = util_get_verbosity();
if (ticks_per_second <= 0)
{
util_dprintf(0, "Couldn't get the value of _SC_CLK_TCK!\n");
return_code(ERR_INTERNAL);
}
util_set_verbosity(0); /* no expensive error-checking */
/*
* all
*/
util_printf("Beginning trav test\n");
startTime = (times(&timeBuf) *1.0) / ticks_per_second;
for (i = 0; i < numTravs; ++i)
{
for (trav_open(&trav, root, AB_TRAV_ALL);
(obj = trav_next(&trav)) != NULL; )
{
}
trav_close(&trav);
}
endTime = (times(&timeBuf) *1.0) / ticks_per_second;
util_printf("end of trav test\n");
totalTravTime = (endTime - startTime);
oneTravTime = totalTravTime/numTravs;
util_printf("one ALL traversal time: %g\n", oneTravTime);
/*
* salient
*/
startTime = (times(&timeBuf) *1.0) / ticks_per_second;
for (i = 0; i < numTravs; ++i)
{
for (trav_open(&trav, root, AB_TRAV_SALIENT);
(obj = trav_next(&trav)) != NULL; )
{
}
trav_close(&trav);
}
endTime = (times(&timeBuf) *1.0) / ticks_per_second;
util_printf("end of trav test\n");
totalTravTime = (endTime - startTime);
oneTravTime = totalTravTime/numTravs;
util_printf("one SALIENT traversal time: %lg\n", oneTravTime);
epilogue:
util_set_verbosity(oldVerbosity);
return return_value;
}
#endif /* DEBUG */
/*
* Actually sets the tree up for code generation.
*/
static int
abmfP_prepare_tree(ABObj project)
{
ABObj module = NULL;
AB_TRAVERSAL trav;
StringList proj_callbacks = NULL;
ABObj obj = NULL;
AB_TRAVERSAL allTrav;
ABObj callbackScopeObj;
STRING funcName = NULL;
ABObj parent = NULL;
/*
* Create extra cgen data for each object
*/
abmfP_create_obj_data_for_project(project);
for(trav_open(&trav, project, AB_TRAV_MODULES);
(module = trav_next(&trav)) != NULL; )
{
abmfP_create_obj_data_for_module(module);
}
trav_close(&trav);
proj_callbacks = mfobj_get_proj_data(project)->callbacks;
for (trav_open(&allTrav, project,
AB_TRAV_ALL | AB_TRAV_MOD_PARENTS_FIRST | AB_TRAV_MOD_SAFE);
(obj = trav_next(&allTrav)) != NULL; )
{
module = obj_get_module(obj);
if (obj_is_action(obj) && (obj_get_func_type(obj) == AB_FUNC_USER_DEF))
{
/*
* we have a user-defined callback. decide where to put it
*/
funcName = obj_get_func_name(obj);
callbackScopeObj = abmfP_find_callback_scope(project, funcName);
if (callbackScopeObj == NULL)
{
/* doesn't exist */
if (obj_is_intra_module(obj) &&
!obj_is_project(obj_get_from(obj)))
{
strlist_add_str(mfobj_get_module_data(module)->callbacks,
funcName, (void *)obj);
}
else
{
strlist_add_str(mfobj_get_proj_data(project)->callbacks,
funcName, (void *)obj);
if (obj_is_project(obj_get_from(obj)))
mfobj_set_flags(obj, CGenFlagWriteDefToProjFile);
}
}
else
{
/*
* It exists - see if it's in the right place...
*/
if ( obj_is_module(callbackScopeObj)
&& (callbackScopeObj != module))
{
/*
* it's in more than one module - put it in the project
*/
int str_index = 0;
ABObj originalConn = NULL;
StringList moduleCallbacks =
mfobj_get_module_data(callbackScopeObj)
->callbacks;
str_index =
strlist_get_str_index(moduleCallbacks, funcName);
strlist_get_str(moduleCallbacks, str_index,
(void **)&originalConn);
if (originalConn != NULL)
{
mfobj_set_flags(originalConn,
CGenFlagWriteDefToProjFile);
}
strlist_remove_index(moduleCallbacks, str_index);
strlist_add_str(
mfobj_get_proj_data(project)->callbacks,
funcName, (void *)originalConn);
mfobj_set_flags(obj, CGenFlagWriteDefToProjFile);
}
/*
* Mark this as a duplicate, so we only write it once
*/
mfobj_set_flags(obj, CGenFlagIsDuplicateDef);
}
} /* action */
else if ((module != NULL) && (obj_get_write_me(module)))
{
/*
* For some reason, menu titles are of type menu and not label
*/
if (ObjWClassIsLabel(obj))
{
obj->type = AB_TYPE_LABEL;
parent = abmfP_parent(obj);
if ( obj_is_menu(parent)
|| obj_is_menu_ref(parent))
{
obj->part_of = abmfP_parent(obj);
parent->part_of = parent;
}
}
if ( (obj_is_menu(obj) || (obj_is_menu_ref(obj)))
&& (obj_get_class_name(obj) == NULL))
{
obj_set_class_name(obj, istr_string(abmfP_xmMenuShell));
}
} /* obj_get_write_me() */
if ((!(mfobj_get_proj_data(project)->has_ui_obj)) && obj_is_ui(obj))
{
mfobj_get_proj_data(project)->has_ui_obj = TRUE;
}
if (obj_get_type(obj) == AB_TYPE_TERM_PANE)
{
mfobj_get_proj_data(project)->has_terminal = TRUE;
}
} /* trav modules */
trav_close(&allTrav);
return 0;
}
static BOOL
abmfP_obj_has_no_module(ABObj obj)
{
return ((obj == NULL) || (obj_get_module(obj) == NULL));
}
/*
* Creates data ONLY for project-specific things that are not covered
* by the individual modules.
*
* Assumes: project is a project
*/
static int
abmfP_create_obj_data_for_project(ABObj project)
{
AB_TRAVERSAL trav;
ABObj obj = NULL;
CGenProjData projData = NULL;
CGenData objData = NULL;
size_t objDataNumBytes = 0;
int numObjects = 0;
int objCount = 0;
numObjects = 0;
for (trav_open_cond(&trav, project, AB_TRAV_ALL|AB_TRAV_MOD_SAFE,
abmfP_obj_has_no_module);
(obj = trav_next(&trav)) != NULL; )
{
++numObjects;
}
/* don't close trav, yet */
/*
* Create data space for all children
*/
objDataNumBytes = numObjects * sizeof(CGenDataRec);
objData= (CGenData)util_malloc(objDataNumBytes);
memset(objData, 0, objDataNumBytes);
/*
* Assign each obj it's own struct
*/
for (trav_reset(&trav), objCount = 0;
(obj = trav_next(&trav)) != NULL; )
{
obj->cgen_data = (CGenData)&(objData[objCount++]);
mfobj_set_flags(obj, CGenFlagDataIsObj);
}
trav_close(&trav); /* close it, now */
assert(objCount == numObjects);
/*
* Create project-specific data
*/
projData = (CGenProjData)calloc(1, sizeof(CGenProjDataRec));
projData->callbacks = strlist_create();
projData->children_data = objData;
mfobj_set_proj_data(project, projData);
return 0;
}
/*
* Accepts any value (NULL, obj w/o module, ...)
*/
static int
abmfP_create_obj_data_for_module(ABObj objInModule)
{
ABObj module = NULL;
int numObjects = 0;
CGenData objData = NULL;
size_t objDataBytes = 0;
ABObj obj = NULL;
AB_TRAVERSAL trav;
int objCount = 0;
if ( (objInModule == NULL)
|| (mfobj_has_data(objInModule))
|| ((module = obj_get_module(objInModule)) == NULL)
)
{
return 0;
}
/*
* object data is an array of all data for the module.
*/
numObjects = trav_count(module, AB_TRAV_ALL);
objDataBytes = numObjects * sizeof(CGenDataRec);
objData = (CGenData)util_malloc(objDataBytes);
memset(objData, 0, objDataBytes);
if (objData == NULL)
{
util_printf_err(CATGETS(Dtb_project_catd, 1, 36,
"Could not allocate cgen data\n"));
return -1;
}
/*
* Assign a structure to each object
*/
for (trav_open(&trav, module, AB_TRAV_ALL), objCount = 0;
(obj = trav_next(&trav)) != NULL; )
{
if (obj->cgen_data == NULL)
{
obj->cgen_data = (CGenData)&(objData[objCount++]);
mfobj_set_flags(obj, CGenFlagDataIsObj);
}
}
trav_close(&trav);
assert(objCount <= numObjects);
/*
* Create module-specific data
*/
ensure_data_for_module_obj(module);
mfobj_get_module_data(module)->children_data = objData;
return 0;
}
/*
* Makes sure the module has a cgen data associated with it. Will load
* the objects in the module if necessary, if loadFile is TRUE.
*/
static int
ensure_data_for_module_obj(ABObj module)
{
CGenModuleData moduleData = NULL;
ABObj project = NULL;
ABObj newProject = NULL;
if (!obj_is_module(module))
{
return -1;
}
project = obj_get_project(module);
if (module->cgen_data == NULL)
{
module->cgen_data = (CGenData)calloc(sizeof(CGenDataRec), 1);
}
if (mfobj_get_module_data(module) == NULL)
{
moduleData = (CGenModuleData)calloc(sizeof(CGenModuleDataRec), 1);
moduleData->callbacks = strlist_create();
mfobj_set_module_data(module, moduleData);
}
return 0;
}
#ifdef DEBUG
static int
dump_callbacks(ABObj project)
{
ABObj module = NULL;
AB_TRAVERSAL moduleTrav;
StringList callbacks = NULL;
util_dprintf(0, "\n***** CALLBACKS *****\n");
util_dprintf(0, "project callbacks\n");
callbacks = mfobj_get_proj_data(project)->callbacks;
if (callbacks != NULL)
{
strlist_dump(callbacks);
}
for (trav_open(&moduleTrav, project, AB_TRAV_MODULES);
(module = trav_next(&moduleTrav)) != NULL; )
{
util_dprintf(0, "module '%s' callbacks\n", util_strsafe(obj_get_name(module)));
callbacks = mfobj_get_module_data(module)->callbacks;
if (callbacks != NULL)
{
strlist_dump(callbacks);
}
}
trav_close(&moduleTrav);
util_dprintf(0,"\n");
return 0;
}
/*
* Checks tree and aborts if an error is found.
*/
static int
debug_verify_tree(ABObj root)
{
AB_TRAVERSAL trav;
char name[256];
ABObj obj = NULL;
*name = 0;
if (!debugging())
{
return 0;
}
util_dprintf(1, "Examining tree for defects.\n");
/*
* Do the standard verification
*/
if (obj_tree_verify(root) < 0)
{
util_dprintf(1, "Project tree is corrupt! Aborting.\n");
abort();
}
/*
* Perform more code-generator specific checks
*/
for (trav_open(&trav, root, AB_TRAV_ALL);
(obj = trav_next(&trav)) != NULL; )
{
if (obj_is_ui(obj))
{
if ( (obj_get_write_me(obj_get_module(obj)))
&& (obj_get_name(obj) == NULL) )
{
util_dprintf(1, "Object has no name: %s\n",
obj_get_safe_name(obj, name, 256));
abort();
}
}
}
trav_close(&trav);
return 0;
}
#endif /* DEBUG */
#ifdef DEBUG /* performance testing */
static int
get_cur_time(double *realTimeOut, double *cpuTimeOut)
{
long ticks_per_second = sysconf(_SC_CLK_TCK);
struct tms timeInfo;
double realTime = times(&timeInfo);
double cpuTime = timeInfo.tms_utime + timeInfo.tms_stime
+ timeInfo.tms_cutime + timeInfo.tms_cstime;
*realTimeOut = realTime / CLK_TCK;
*cpuTimeOut = cpuTime / CLK_TCK;
return 0;
}
#endif /* DEBUG */