2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * $XConsortium: cgen_utils.c /main/7 1996/10/02 10:56:38 drk $
26 * @(#)cgen_utils.c 1.6 01 Jun 1994
28 * RESTRICTED CONFIDENTIAL INFORMATION:
30 * The information in this document is subject to special
31 * restrictions in a confidential disclosure agreement between
32 * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
33 * document outside HP, IBM, Sun, USL, SCO, or Univel without
34 * Sun's specific written approval. This document and all copies
35 * and derivative works thereof must be returned or destroyed at
38 * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
44 * cgen_utils.c - utility functions for Code Generator Window and
49 #define _POSIX_SOURCE 1
52 #include <sys/types.h>
64 #include <sys/param.h>
69 #include <Dt/TermPrim.h>
72 #include <ab_private/ab.h>
73 #include <ab_private/abobj_set.h>
74 #include <ab_private/proj.h>
75 #include <ab_private/cgen.h>
76 #include <ab_private/obj_notify.h>
77 #include <ab_private/util.h>
78 #include <ab_private/trav.h>
79 #include <ab_private/strlist.h>
81 #include "dtbuilder.h"
82 #include "cgen_win_ui.h"
83 #include "palette_ui.h"
84 #include "cgen_props_ui.h"
87 #define INVALID_PID ((pid_t)-1)
88 #define EXIT_SLEEP_SECONDS (10) /* see subprocess_exit() */
89 #define CHILD_PID_LIST_SIZE EXIT_SLEEP_SECONDS
91 /* WARNING: If more dtcodegen options are added, then
92 * MAX_CGEN_FIXED_ARGS must be incremented!
94 * MAX_CGEN_FIXED_ARGS = dtcodegen, -changed, -nomerge, -v or -s,
95 * -main, -p, <project_name>, NULL, +2(extra) = 10
97 #define MAX_CGEN_FIXED_ARGS 10
110 CGenOptions CodeGenOptions;
111 StringList user_env_vars = NULL;
112 StringList module_list = NULL;
113 static CG_GOAL user_goal = CG_GOAL_UNDEF;
115 static XtInputId input_proc_id = (XtInputId)-1;
116 static int status_pipe_read = -1;
117 static int status_pipe_write = -1;
118 static Widget output_termWidget = NULL;
119 static Widget input_termWidget = NULL;
120 static Widget make_run_item = NULL;
121 static Widget gen_code_item = NULL;
122 static Widget make_item = NULL;
123 static Widget run_item = NULL;
124 static Widget abort_item = NULL;
125 static Widget cgen_props_item = NULL;
126 static Widget gen_code_button = NULL;
127 static Widget make_run_button = NULL;
128 static Widget make_button = NULL;
129 static Widget run_button = NULL;
130 static Widget abort_button = NULL;
131 static Widget cur_dir_text = NULL;
132 static ISTRING termSlaveDeviceName = NULL;
133 static pid_t child_pid_list[CHILD_PID_LIST_SIZE];
134 static pid_t actual_process_pgid = INVALID_PID;
135 static pid_t abortingPID = INVALID_PID;
138 * Places to find various commands
140 static STRING dtcodegenCmdList[] =
142 "", /* exe-dir filled in at run time */
143 "", /* exe-dir/../abmf : filled in at runtime */
145 "/usr/dt/bin/dtcodegen",
149 static STRING makeCmdList[] =
153 "/usr/dist/exe/make",
154 "/usr/dist/local/exe/make",
159 static BOOL cgen_inited = FALSE;
161 #define cgen_check_init() (cgen_inited? 0:cgen_init())
163 static int util_fdsync(int fd); /* REMIND: move to libAButil*/
164 static int print_to_term(STRING msg);
165 static int send_output_to_term(void);
166 static int term_execute_command(CG_SUBCOMMAND cmd_code, STRING cmd, STRING argv[]);
167 static int get_slave_device_name(void);
168 static int print_failure_message(CG_SUBCOMMAND cmd_code, int exit_code);
169 static int print_internal_err_message(void);
170 static int print_success_message(void);
171 static int print_cmd_not_found_message(STRING cmd);
172 static int print_death_message(void);
173 static int print_exit_message(int exit_code);
174 static int print_abort_message(void);
175 static int create_status_pipe(void);
176 static int destroy_status_pipe(void);
177 static int write_to_status_pipe(
178 CG_STATUS status_code,
179 CG_SUBCOMMAND cmd_code,
182 static int read_from_status_pipe(
183 CG_STATUS *status_code_out,
184 CG_SUBCOMMAND *cmd_code_out,
185 void **status_data_out
187 static int careful_kill_group(pid_t pgid);
188 static int goto_ready_state(void);
189 static int goto_busy_state(void);
190 static int cgenP_abort(void);
191 static int cgen_set_title(STRING projectName);
192 static int cgen_set_project_dir(STRING dir);
193 static int cgen_obj_name_changed_cb(ObjEvAttChangeInfo evInfo);
194 static void cgen_abort_at_exit(void);
195 static STRING cgenP_get_env_var(STRING varName);
196 static int cgenP_put_env_var(STRING varName, STRING varValue);
197 static int set_props_proj_name(STRING);
198 static int obj_renamedOCB(ObjEvAttChangeInfo);
199 static int obj_destroyedOCB(ObjEvDestroyInfo);
200 static int obj_updateOCB(ObjEvUpdateInfo info);
201 static int do_user_action(
205 static int build_dtcodegen_cmd_list(STRING *cmdList);
206 static int build_dtcodegen_arg_list(STRING *argList, int *iInOut);
207 static int check_path(void);
208 static int check_path_to_cmd(STRING *cmdList, BOOL *allowWarnUserInOut);
209 static int check_makefile(BOOL *continueOut);
210 static int cgenP_makefile_is_for_project(STRING fileName, ABObj project);
211 static BOOL strings_exist_in_file(StringList strings, FILE *file);
212 static int destroy_makefile(void);
213 static int destroy_links_to_file(STRING fileName);
214 static int move_file_to_backup(STRING fileName);
215 static int add_obj_file_name(
216 StringList fileNames,
220 static BOOL all_files_exist(ABObj project);
221 static int select_command(STRING *cmdList, STRING *cmdOut);
222 static BOOL command_exists(STRING cmd, STRING path);
223 static int save_done_cb(int status);
224 static int add_child_to_list(pid_t child_pid);
225 static int wait_for_child(void);
226 static STRING cvt_type_to_ident(
231 static Boolean path_is_executable(
237 static void popdown_cgen_window(
239 XtPointer client_data,
243 static void pipe_data_ready_proc(
244 XtPointer client_data,
249 static int subprocess_exit(int exit_code);
251 static int exec_generate_code(void);
252 static int exec_make(void);
253 static int exec_run(void);
255 static int exec_generate_proj(void);
256 static int exec_generate_main(void);
257 static int exec_generate_specific_files(void);
258 static int exec_generate_specific_files_and_main(void);
260 #define util_fdclose(fd) \
271 * Exit cmd_code and exit_code are the command that was previously run
272 * and its exit status.
274 static int exec_next_command(
275 CG_SUBCOMMAND cmd_code, int exit_code);
276 static int exec_next_command_for_gen_code(
277 CG_SUBCOMMAND cmd_code, int exit_code);
278 static int exec_next_command_for_make(
279 CG_SUBCOMMAND cmd_code, int exit_code);
280 static int exec_next_command_for_run(
281 CG_SUBCOMMAND cmd_code, int exit_code);
282 static int exec_next_command_for_build_and_run(
283 CG_SUBCOMMAND cmd_code, int exit_code);
284 static int exec_first_build_and_run_command(void);
287 * This should go at the beginning of all public entry points. It
288 * checks to see if the request can be processed.
290 #define public_entry_point() \
291 if (AB_cgen_win == NULL) {return 0;} else {cgen_check_init();}
294 /*************************************************************************
296 ** PUBLIC ENTRY POINTS **
298 *************************************************************************/
301 cgen_show_codegen_win(
305 Widget shell = (Widget) NULL;
308 if (AB_cgen_win == (Widget) NULL)
311 * Module initialization
313 dtbCgenWinMainwindowInfo_clear(&dtb_cgen_win_mainwindow);
315 dtb_cgen_win_mainwindow_initialize(
316 &dtb_cgen_win_mainwindow, dtb_get_toplevel_widget());
317 AB_cgen_win = dtb_cgen_win_mainwindow.mainwindow_mainwin;
318 shell = dtb_cgen_win_mainwindow.mainwindow;
320 /* Set up local handles for important widgets */
321 make_run_item = dtb_cgen_win_mainwindow.menubar_File_item_file_pulldown_items.Make_Run_item;
322 gen_code_item = dtb_cgen_win_mainwindow.menubar_File_item_file_pulldown_items.Generate_Code_item;
323 make_item = dtb_cgen_win_mainwindow.menubar_File_item_file_pulldown_items.Make_item;
324 run_item = dtb_cgen_win_mainwindow.menubar_File_item_file_pulldown_items.Run_item;
325 abort_item = dtb_cgen_win_mainwindow.menubar_File_item_file_pulldown_items.Abort_item;
326 cgen_props_item = dtb_cgen_win_mainwindow.menubar_Options_item_options_pulldown_items.Generator_item;
327 cur_dir_text = dtb_cgen_win_mainwindow.proj_dir;
328 gen_code_button = dtb_cgen_win_mainwindow.gen_code_btn;
329 make_button = dtb_cgen_win_mainwindow.make_btn;
330 run_button = dtb_cgen_win_mainwindow.run_btn;
331 make_run_button = dtb_cgen_win_mainwindow.make_run_btn;
332 abort_button = dtb_cgen_win_mainwindow.abort_btn;
333 output_termWidget= dtb_cgen_win_mainwindow.output_termp;
334 input_termWidget = dtb_cgen_win_mainwindow.input_termp;
337 * Setup window to participate in dtbuilder window protocol
339 ab_register_window(AB_cgen_win, AB_WIN_WINDOW, WindowHidden,
340 AB_toplevel, AB_WPOS_STACK_CENTER,
341 popdown_cgen_window, NULL);
343 cgen_notify_new_project(proj_get_project());
344 obj_add_rename_callback( cgen_obj_name_changed_cb,
345 "cgen_obj_name_changed_cb");
347 XtRealizeWidget(shell);
349 build_dtcodegen_cmd_list(dtcodegenCmdList);
352 * Make sure the application being run can find its resource file
353 * By setting this via cgenP_put_env_var(), the user has the
354 * option of resetting it to its original value.
356 if (cgenP_get_env_var("XAPPLRESDIR") == NULL)
358 cgenP_put_env_var("XAPPLRESDIR", ".");
361 atexit(cgen_abort_at_exit); /* make sure children die! */
363 ab_show_window(AB_cgen_win);
365 /* Turn off the cursor for the output only termpane */
366 DtTermDisplaySend(output_termWidget, (unsigned char *)"
\e[?25l", strlen("
\e[?25l"));
377 for (i = 0; i < XtNumber(child_pid_list); ++i)
379 child_pid_list[i] = INVALID_PID;
386 build_dtcodegen_cmd_list(STRING *cmdList)
388 char exeDirCmd[MAXPATHLEN+1];
389 STRING exeDir = NULL;
392 exeDir = dtb_get_exe_dir();
398 if (*(cmdList[0]) == 0)
400 sprintf(exeDirCmd, "%s/dtcodegen", exeDir);
401 cmdList[0] = strdup(exeDirCmd);
404 if (*(cmdList[1]) == 0)
406 sprintf(exeDirCmd, "%s/../abmf/dtcodegen", exeDir);
407 cmdList[1] = strdup(exeDirCmd);
417 XtPointer client_data,
421 /* If its secondary dialogs are open, close them first to
422 * ensure their state is recorded properly.
424 if (AB_cgen_prop_dialog && ab_window_is_open(AB_cgen_prop_dialog))
425 ui_win_show(AB_cgen_prop_dialog, False, XtGrabNone);
426 if (AB_cgen_env_dialog && ab_window_is_open(AB_cgen_env_dialog))
427 ui_win_show(AB_cgen_env_dialog, False, XtGrabNone);
429 ui_win_show(widget, False, XtGrabNone);
434 cgen_notify_new_project(ABObj project)
436 public_entry_point(); /* see if we'll allow this entry */
437 cgen_set_title(project == NULL? NULL : obj_get_name(project));
438 cgen_set_project_dir(NULL);
444 cgen_notify_new_directory(STRING dir)
446 public_entry_point();
447 cgen_set_project_dir(dir);
448 cgenP_sync_up_dir(); /* NOTE: assuming dir = project dir */
456 public_entry_point();
457 return cgenP_abort();
462 cgen_abort_at_exit(void)
468 cgen_notify_props_new_proj(
474 ret = set_props_proj_name(project == NULL? NULL : obj_get_name(project));
479 cgenP_init_props_module_list(
483 ABObj proj = proj_get_project();
487 for (trav_open(&trav, proj, AB_TRAV_MODULES);
488 (obj= trav_next(&trav)) != NULL; )
490 if (obj_is_defined(obj))
492 ui_list_add_item(mod_list, obj_get_name(obj), 0);
499 * Initialize Code Generator Props:
500 * Add callbacks for object rename & destroy
506 obj_add_rename_callback(obj_renamedOCB, "cgen_prop_init");
507 obj_add_update_callback(obj_updateOCB, "cgen_prop_init");
508 obj_add_destroy_callback(obj_destroyedOCB, "cgen_prop_init");
516 do_user_action(CG_GOAL_GEN_CODE, cmd);
524 do_user_action(CG_GOAL_MAKE , cmd);
532 do_user_action(CG_GOAL_RUN, cmd);
540 do_user_action(CG_GOAL_MAKE_AND_RUN, cmd);
544 /*************************************************************************
545 *************************************************************************
547 ** PRIVATE ENTRY POINTS **
549 *************************************************************************
550 *************************************************************************/
553 /*************************************************************************
555 ** Handle the terminal emulator **
557 *************************************************************************/
560 * Prints the string to the terminal. Always flushes.
563 print_to_term(STRING msg)
568 if ((rc = get_slave_device_name()) < 0)
572 fp = util_fopen_locked(istr_string(termSlaveDeviceName), "w");
577 fprintf(fp, "%s", msg);
583 * Sends stdout and stderr to term window
586 send_output_to_term()
588 static BOOL done = FALSE;
595 if ((rc = get_slave_device_name()) < 0)
601 freopen(istr_string(termSlaveDeviceName), "w", stdout);
602 freopen(istr_string(termSlaveDeviceName), "w", stderr);
609 term_execute_command(CG_SUBCOMMAND cmd_code, STRING cmd, STRING argv[])
611 CG_STATUS status_code = CG_STATUS_UNDEF;
614 pid_t rc_pid = INVALID_PID;
615 pid_t watchdog_pid = INVALID_PID;
616 int child_status = 0;
618 int i= 0, msg_size = 0;
620 if (actual_process_pgid != INVALID_PID)
624 if ((rc = get_slave_device_name()) < 0)
633 msg_size = strlen("====> Running: ");
634 for (i = 0; argv[i] != NULL; ++i)
636 msg_size += strlen(argv[i]) + 1;
638 msg = (STRING) XtMalloc(msg_size + 1); /* Add 1 for NULL */
639 strcpy(msg, "====> Running: ");
641 for (i= 1; argv[i] != NULL; ++i)
644 strcat(msg, argv[i]);
650 * Clean up (possible) zombie watchdog process(es)
654 create_status_pipe();
655 watchdog_pid = fork();
656 if (watchdog_pid == (pid_t)-1)
659 util_printf_err("Could not create subprocess: %s\n",
661 watchdog_pid = INVALID_PID;
662 write_to_status_pipe(CG_STATUS_ERROR, cmd_code, (void*)0);
664 else if (watchdog_pid == 0)
666 /* child - "watchdog" process */
668 pid_t actual_process_pid = INVALID_PID;
671 * For some reason, if the SIGCHLD signal is not blocked,
672 * waitpid() returns -1, with errno == EINTR. This is exactly
673 * the opposite of the behavior I would expect, but it seems
678 sigemptyset(&signals);
679 sigaddset(&signals, SIGCHLD);
680 sigprocmask(SIG_BLOCK, &signals, NULL);
683 util_fdclose(status_pipe_read);
685 send_output_to_term();
686 actual_process_pid = fork();
687 if (actual_process_pid == INVALID_PID)
690 fprintf(stderr, "Could not create subprocess: %s\n",
692 write_to_status_pipe(CG_STATUS_ERROR, cmd_code, (void*)0);
695 else if (actual_process_pid == 0)
697 /* grandchild - becomes the program we are actually running */
698 int num_env_vars = strlist_get_num_strs(user_env_vars);
700 STRING var_name = NULL;
701 STRING var_value = NULL;
702 STRING putenv_var = NULL;
703 int putenv_var_size = 0;
705 setpgid(0,0); /* make process group leader */
706 write_to_status_pipe(CG_STATUS_STARTED, cmd_code, (void*)getpgrp());
708 for (i = 0; i < num_env_vars; ++i)
711 var_name = strlist_get_str(user_env_vars,i, (void **)&var_value);
712 if (!util_strempty(var_value))
714 putenv_var_size = strlen(var_name) + strlen(var_value) + 2;
715 /* +2 for "=" and NULL */
716 putenv_var = (STRING)util_malloc(putenv_var_size);
717 sprintf(putenv_var, "%s=%s", var_name, var_value);
721 putenv_var_size = strlen(var_name) + 2;
722 putenv_var = (STRING)util_malloc(putenv_var_size);
723 sprintf(putenv_var, "%s=", var_name);
725 util_putenv(putenv_var);
729 * Close status pipe and start command!
731 util_fdclose(status_pipe_read);
732 util_fdclose(status_pipe_write);
733 if (execvp(cmd, argv) == -1)
738 } /* grandchild (actual work process) */
741 /* child ("watchdog" process) */
742 int grandchild_status = 0;
743 pid_t rc_pid = INVALID_PID; /* returned pid */
745 /*util_dprintf(3, "process launched: %ld\n", (long)actual_process_pid);*/
747 rc_pid = waitpid(actual_process_pid, &grandchild_status, 0);
748 /*printf("frontline: child done!\n");*/
749 if (rc_pid == INVALID_PID)
751 /* damn! an error occured... */
752 /*printf("frontline: error waiting for child! (%s)\n",
753 util_strsafe(strerror(errno)));*/
754 status_code = CG_STATUS_ERROR;
760 if (WIFEXITED(grandchild_status))
762 /* grandchild exited */
763 /* printf("frontline: grandchild exited(%d)\n",
764 WEXITSTATUS(grandchild_status));*/
765 status_code = CG_STATUS_EXITED;
766 exit_code = WEXITSTATUS(grandchild_status);
768 else if (WIFSIGNALED(grandchild_status))
770 /* child was killed by uncaught signal */
771 int kill_signal = WTERMSIG(grandchild_status);
772 STRING signalName = NULL;
773 time_t signalTime = time(NULL);
774 BOOL coreDumped = FALSE;
775 struct stat fileInfo;
776 /*printf("frontline: child signalled(%d)\n", kill_signal);*/
778 status_code = CG_STATUS_SIGNALLED;
779 exit_code = kill_signal;
781 if (stat("core", &fileInfo) == 0)
783 if (labs(difftime(signalTime, fileInfo.st_mtime)) < 5)
791 case SIGABRT: signalName = "Aborted";
793 case SIGALRM: signalName = "Uncaught alarm";
795 #ifdef SIGBUS /* SIGBUS is not POSIX */
796 case SIGBUS: signalName = "Bus error";
799 case SIGFPE: signalName = "Arithmetic exception";
801 case SIGHUP: signalName = "Hangup";
803 case SIGILL: signalName = "Illegal instruction";
805 case SIGINT: signalName = "Interrupted";
807 case SIGKILL: signalName = "Killed";
809 case SIGPIPE: signalName = "Write to bad pipe";
811 case SIGQUIT: signalName = "Quit";
813 case SIGSEGV: signalName = "Segmentation fault";
815 case SIGTERM: signalName = "Terminated";
819 static char sigmsg[30];
820 sprintf(sigmsg, "Uncaught signal %d", kill_signal);
825 fprintf(stderr, "====> %s", signalName);
828 fprintf(stderr, " (Core dumped)");
830 fprintf(stderr, "\n");
834 if (status_pipe_write >= 0)
836 write_to_status_pipe(status_code, cmd_code, (void*)exit_code);
837 util_fdclose(status_pipe_write);
839 subprocess_exit(exit_code);
840 } /* child (watchdog) */
842 /* This block should never execute */
843 assert(("Bad block executed",TRUE));
849 add_child_to_list(watchdog_pid);
850 util_fdclose(status_pipe_write);
858 * Gets the slave device name and puts it into the file variable
861 get_slave_device_name()
863 String deviceName = NULL;
865 if (termSlaveDeviceName != NULL)
870 if (termSlaveDeviceName == NULL)
872 XtVaGetValues(output_termWidget, DtNtermSlaveName, &deviceName, NULL);
873 if (deviceName != NULL)
875 termSlaveDeviceName= istr_create(deviceName);
876 /*util_dprintf(2,"slavename: '%s'\n", util_strsafe(deviceName));*/
878 } /* deviceName == NULL */
880 return (termSlaveDeviceName == NULL ? -1 : 0);
884 /*************************************************************************
886 ** Implement the functions **
888 *************************************************************************/
893 ABObj project= proj_get_project();
894 STRING project_name= NULL;
900 project_name = obj_get_name(project);
901 if (project_name == NULL)
906 switch (CodeGenOptions.cmd_flag)
908 case CG_GEN_SPECIFIC_FILES_FLAG:
909 exec_generate_specific_files();
912 case CG_GEN_SPECIFIC_FILES_AND_MAIN_FLAG:
913 exec_generate_specific_files_and_main();
916 case CG_GEN_MAIN_FLAG:
917 exec_generate_main();
920 case CG_GEN_PROJ_FLAG:
921 exec_generate_proj();
933 int rc = 0; /* return code */
934 ABObj project= proj_get_project();
935 STRING project_name= NULL;
936 STRING argv[MAX_CGEN_FIXED_ARGS];
944 project_name = obj_get_name(project);
945 if (project_name == NULL)
950 for (i = 0; i < MAX_CGEN_FIXED_ARGS; i++)
954 if ((rc = build_dtcodegen_arg_list(argv, &i)) < 0)
959 argv[i]= "-main"; i++;
961 argv[i]= project_name; i++;
964 term_execute_command(CG_CMD_GEN_CODE, argv[0], argv);
971 int rc = 0; /* return code */
972 ABObj project= proj_get_project();
973 STRING project_name= NULL;
974 STRING argv[MAX_CGEN_FIXED_ARGS];
982 project_name= obj_get_name(project);
983 if (project_name == NULL)
988 for (i = 0; i < MAX_CGEN_FIXED_ARGS; i++)
992 if ((rc = build_dtcodegen_arg_list(argv, &i)) < 0)
998 argv[i]= project_name; i++;
1000 term_execute_command(CG_CMD_GEN_CODE, argv[0], argv);
1006 exec_generate_specific_files()
1008 int returnValue = 0;
1009 int rc = 0; /* return code */
1010 ABObj project= proj_get_project();
1011 STRING project_name= NULL;
1013 int argv_size = MAX_CGEN_FIXED_ARGS;
1014 int i, n, num_args, arg_count, num_mods;
1016 if (project == NULL)
1020 project_name= obj_get_name(project);
1021 if (project_name == NULL)
1026 num_mods = strlist_get_num_strs(CodeGenOptions.module_list);
1027 argv_size += num_mods;
1028 argv = (STRING *)util_malloc(argv_size * sizeof(STRING));
1029 for (i = 0; i < argv_size; i++)
1033 if ((rc = build_dtcodegen_arg_list(argv, &arg_count)) < 0)
1039 argv[arg_count]= "-p"; arg_count++;
1040 argv[arg_count]= project_name; arg_count++;
1042 num_args = arg_count + num_mods;
1043 for (i = arg_count, n = 0; i < num_args; i++, n++)
1045 argv[i] = strlist_get_str(CodeGenOptions.module_list, n, (void **)NULL);
1047 argv[num_args] = NULL;
1049 term_execute_command(CG_CMD_GEN_CODE, argv[0], argv);
1057 exec_generate_specific_files_and_main()
1059 int returnValue = 0;
1060 int rc = 0; /* return code */
1061 ABObj project= proj_get_project();
1062 STRING project_name= NULL;
1064 int argv_size = MAX_CGEN_FIXED_ARGS;
1065 int i, n, num_args, arg_count, num_mods;
1067 if (project == NULL)
1071 project_name= obj_get_name(project);
1072 if (project_name == NULL)
1077 num_mods = strlist_get_num_strs(CodeGenOptions.module_list);
1078 argv_size += num_mods;
1079 argv = (STRING *)util_malloc(argv_size * sizeof(STRING));
1080 for (i = 0; i < argv_size; i++)
1084 if ((rc = build_dtcodegen_arg_list(argv, &arg_count)) < 0)
1090 argv[arg_count]= "-main"; arg_count++;
1091 argv[arg_count]= "-p"; arg_count++;
1092 argv[arg_count]= project_name; arg_count++;
1094 num_args = arg_count + num_mods;
1095 for (i = arg_count, n = 0; i < num_args; i++, n++)
1097 argv[i] = strlist_get_str(CodeGenOptions.module_list, n, (void **)NULL);
1099 argv[num_args] = NULL;
1101 term_execute_command(CG_CMD_GEN_CODE, argv[0], argv);
1110 * Builds the code generator options that are common to all the code
1113 * argList[0] = the executable
1115 * The individual strings returned in argList are pointers to static
1116 * storage and should not be freed by the caller.
1118 * Returns the number of arguments that were added.
1120 * ASSUMES: the argList array is large enough to handle all args, plus a NULL
1123 build_dtcodegen_arg_list(STRING *argList, int *iInOut)
1125 int returnValue = 0;
1128 int numArgsAdded = 0;
1129 STRING dtcodegenCmd = NULL;
1131 if ((rc = select_command(dtcodegenCmdList, &dtcodegenCmd)) < 0)
1133 print_cmd_not_found_message("dtcodegen");
1138 argList[i++]= dtcodegenCmd;
1139 argList[i++]= "-changed"; /* everybody gets this one */
1141 if (CodeGenOptions.no_merge)
1143 argList[i++] = "-nomerge";
1147 switch (CodeGenOptions.verbosity)
1149 case CG_VERBOSITY_SILENT:
1150 argList[i++] = "-s";
1154 case CG_VERBOSITY_VERBOSE:
1155 argList[i++] = "-v";
1163 if (returnValue >= 0)
1165 /* successful - return i */
1166 returnValue = numArgsAdded;
1176 int rc = 0; /* return code */
1179 BOOL continueMake = FALSE;
1181 rc= check_makefile(&continueMake);
1182 if ((rc < 0) || (!continueMake))
1187 if ((rc = select_command(makeCmdList, &cmd)) < 0)
1189 print_cmd_not_found_message(makeCmdList[0]);
1194 argv[1] = CodeGenOptions.make_args;
1196 term_execute_command(CG_CMD_MAKE, argv[0], argv);
1204 ABObj project= NULL;
1205 char executable_name[1024];
1208 *executable_name = 0;
1211 project= proj_get_project();
1212 if ((project == NULL) || (obj_get_name(project) == NULL))
1217 cvt_type_to_ident(obj_get_name(project), executable_name, 1024);
1218 sprintf(cmd, "./%s", executable_name);
1220 argv[1] = CodeGenOptions.run_args;
1222 term_execute_command(CG_CMD_RUN, argv[0], argv);
1229 * cmd_code is the code of the command that just finished. Executes
1230 * the next command necessary to achieve the user's goal.
1232 * If cmd_code is CG_CMD_UNDEF, assumes that no commands have been
1233 * issued, and issues the first command to achieve the goal.
1236 exec_next_command(CG_SUBCOMMAND cmd_code, int exit_code)
1238 int return_value= 0;
1240 if (cmd_code == CG_CMD_UNDEF)
1242 print_to_term("\n\n");
1248 case CG_GOAL_GEN_CODE:
1249 return_value= exec_next_command_for_gen_code(cmd_code, exit_code);
1253 return_value= exec_next_command_for_make(cmd_code, exit_code);
1257 return_value= exec_next_command_for_run(cmd_code, exit_code);
1260 case CG_GOAL_MAKE_AND_RUN:
1261 return_value = exec_next_command_for_build_and_run(cmd_code, exit_code);
1266 return_value= ERR_INTERNAL;
1270 if (return_value < 0)
1275 return return_value;
1279 exec_next_command_for_gen_code(CG_SUBCOMMAND cmd_code, int exit_code)
1281 int rc= 0; /* return code */
1282 exit_code = exit_code; /* avoid warning */
1287 rc= exec_generate_code();
1290 case CG_CMD_GEN_CODE:
1291 print_success_message();
1302 exec_next_command_for_make(CG_SUBCOMMAND cmd_code, int exit_code)
1304 exit_code = exit_code; /* avoid warning */
1309 case CG_CMD_GEN_CODE: /* was run to get Makefile */
1314 print_success_message();
1325 exec_next_command_for_run(CG_SUBCOMMAND cmd_code, int exit_code)
1334 print_exit_message(exit_code);
1345 exec_next_command_for_build_and_run(CG_SUBCOMMAND cmd_code, int exit_code)
1350 /* this may do a generate and/or a make */
1351 exec_first_build_and_run_command();
1354 case CG_CMD_GEN_CODE:
1363 print_exit_message(exit_code);
1375 exec_first_build_and_run_command()
1377 int return_value= 0;
1378 if (!util_file_exists("Makefile"))
1380 return_value= exec_generate_proj();
1384 return_value= exec_make();
1386 return return_value;
1391 wait_for_child(void)
1393 pid_t childPid = INVALID_PID;
1394 pid_t rcPid = INVALID_PID;
1398 for (i = 0; i < XtNumber(child_pid_list); ++i)
1400 if ((childPid = child_pid_list[i]) == INVALID_PID)
1404 if ( ((rcPid = waitpid(childPid, (int*)0, WNOHANG)) == childPid)
1405 || (kill(childPid,0) == -1))
1407 child_pid_list[i] = INVALID_PID;
1417 add_child_to_list(pid_t childPid)
1421 int attemptCount = 0;
1422 int maxAttempts = EXIT_SLEEP_SECONDS+2;
1424 for (attemptCount = 0; (!added) && (attemptCount < maxAttempts);
1427 if (attemptCount > 0)
1429 sleep(1); /* wait for child to exit, making room */
1431 wait_for_child(); /* make some room */
1433 for (i = 0; i < XtNumber(child_pid_list); ++i)
1435 if (child_pid_list[i] == INVALID_PID)
1437 child_pid_list[i] = childPid;
1448 subprocess_exit(int exit_code)
1450 if (status_pipe_write >= 0)
1452 util_fdsync(status_pipe_write);
1454 util_fdclose(status_pipe_write);
1455 util_fdclose(status_pipe_read);
1458 * On AIX, writing to a pipe and immediately exiting seems to guarantee
1459 * that not all the data will reach the receiving end of the pipe.
1460 * closing the pipe and sleeping for a few seconds seems to work well.
1462 if (util_get_os_type() == AB_OS_AIX)
1464 sleep(EXIT_SLEEP_SECONDS);
1472 print_internal_err_message()
1474 print_to_term("****> UNSUCCESSFUL (Internal failure occurred).\n");
1480 print_failure_message(CG_SUBCOMMAND cmd_code, int exit_code)
1484 sprintf(msg, "****> UNSUCCESSFUL (Command exited with code %d).\n",
1487 user_goal= CG_GOAL_UNDEF;
1494 print_success_message()
1496 print_to_term("====> Completed successfully.\n");
1497 user_goal= CG_GOAL_UNDEF;
1504 print_cmd_not_found_message(STRING cmd)
1510 "****> ERROR - Could not find command '%s'.\n"
1511 "****> Please check your PATH variable (This can be\n"
1512 "****> done via the Options->Environment menu).\n",
1516 user_goal= CG_GOAL_UNDEF;
1523 print_death_message(void)
1527 "****> Program died a horrible, unnatural death, due to an uncaught signal\n");
1529 user_goal = CG_GOAL_UNDEF;
1530 return goto_ready_state();
1535 print_exit_message(int exitCode)
1538 sprintf(msg, "====> Program exited (exit code %d)\n", exitCode);
1540 user_goal= CG_GOAL_UNDEF;
1547 print_abort_message()
1549 print_to_term("\n====> Command aborted.\n");
1550 user_goal= CG_GOAL_UNDEF;
1557 pipe_data_ready_proc(
1558 XtPointer client_data,
1563 BOOL aborted = FALSE;
1564 CG_SUBCOMMAND cmd_code = CG_CMD_UNDEF;
1565 CG_STATUS status_code = CG_STATUS_UNDEF;
1566 void *status_data = NULL;
1567 int int_status_code = 0;
1568 int int_cmd_code = 0;
1570 int kill_signal = 0;
1571 pid_t rc_pid = INVALID_PID;
1572 id = id; /* avoid warning */
1574 /*util_dprintf(3, "rcv - data ready on pipe...\n");*/
1575 if (read_from_status_pipe(&status_code, &cmd_code, &status_data) < 0)
1577 status_code = CG_STATUS_ERROR;
1580 aborted = ( (abortingPID != INVALID_PID)
1581 && (abortingPID == actual_process_pgid) );
1583 switch (status_code)
1585 case CG_STATUS_STARTED:
1586 actual_process_pgid = (pid_t)status_data;
1587 /*util_dprintf(2,"rcv started: %ld\n", (long)actual_process_pgid);*/
1590 case CG_STATUS_EXITED:
1591 exit_code = (int)status_data;
1592 actual_process_pgid = INVALID_PID;
1593 /*util_dprintf(2,"rcv exit(%d)\n", exit_code);*/
1596 /* message gets printed below */
1598 else if ((exit_code != 0) && (cmd_code != CG_CMD_RUN))
1600 print_failure_message(cmd_code, exit_code);
1605 exec_next_command(cmd_code, exit_code);
1609 case CG_STATUS_SIGNALLED:
1610 kill_signal = (int)status_data;
1611 /*util_dprintf(2,"rcv signalled(%d)\n", kill_signal);*/
1612 actual_process_pgid = INVALID_PID;
1616 case CG_STATUS_ERROR:
1617 print_internal_err_message();
1618 if (actual_process_pgid != INVALID_PID)
1620 if (careful_kill_group(actual_process_pgid) >= 0)
1622 actual_process_pgid = INVALID_PID;
1629 if (actual_process_pgid != INVALID_PID)
1631 if (careful_kill_group(actual_process_pgid) >= 0)
1633 actual_process_pgid = INVALID_PID;
1642 print_abort_message();
1646 if (actual_process_pgid == INVALID_PID)
1648 abortingPID = INVALID_PID;
1652 wait_for_child(); /* clean up (possible) zombie watchdog processes */
1658 * We are running a process - desensitize most buttons.
1663 XtSetSensitive(abort_button, True);
1664 XtSetSensitive(abort_item, True);
1666 XtSetSensitive(cgen_props_item, False);
1667 XtSetSensitive(gen_code_button, False);
1668 XtSetSensitive(gen_code_item, False);
1669 XtSetSensitive(make_button, False);
1670 XtSetSensitive(make_item, False);
1671 XtSetSensitive(make_run_button, False);
1672 XtSetSensitive(make_run_item, False);
1673 XtSetSensitive(run_button, False);
1674 XtSetSensitive(run_item, False);
1680 * We are waiting for user input
1685 XtSetSensitive(abort_button, False);
1686 XtSetSensitive(abort_item, False);
1688 XtSetSensitive(cgen_props_item, True);
1689 XtSetSensitive(gen_code_button, True);
1690 XtSetSensitive(gen_code_item, True);
1691 XtSetSensitive(make_button, True);
1692 XtSetSensitive(make_item, True);
1693 XtSetSensitive(make_run_button, True);
1694 XtSetSensitive(make_run_item, True);
1695 XtSetSensitive(run_button, True);
1696 XtSetSensitive(run_item, True);
1703 create_status_pipe(void)
1705 BOOL pipeOpen = TRUE;
1706 /*util_dprintf(2,"create_status_pipe()\n");*/
1708 if ((status_pipe_read < 0) || (status_pipe_write < 0))
1712 destroy_status_pipe();
1716 status_pipe_read = fds[0]; fds[0] = -1;
1717 status_pipe_write = fds[1]; fds[1] = -1;
1720 if ( (input_proc_id == -1)
1721 && (status_pipe_read >= 0)
1722 && (output_termWidget != NULL))
1724 XtAppContext app_context= XtWidgetToApplicationContext(output_termWidget);
1729 (XtPointer)XtInputReadMask,
1730 pipe_data_ready_proc,
1740 util_dprintf(1, "CGEN WINDOW: COULD NOT CREATE STATUS PIPE\n");
1743 return pipeOpen?0:-1;
1748 destroy_status_pipe(void)
1750 /*util_dprintf(2,"destroy_status_pipe()\n");*/
1751 util_fdclose(status_pipe_read);
1752 util_fdclose(status_pipe_write);
1754 if (input_proc_id != -1)
1756 XtRemoveInput(input_proc_id); input_proc_id = -1;
1764 write_to_status_pipe(
1765 CG_STATUS status_code,
1766 CG_SUBCOMMAND cmd_code,
1770 int int_status_code = (int)status_code;
1771 int int_cmd_code= (int)cmd_code;
1773 /*printf("write to pipe: %d %d %d\n",
1774 (int)status_code, (int)cmd_code, (int)status_data);*/
1775 write(status_pipe_write, (void*)&int_status_code, sizeof(int));
1776 write(status_pipe_write, (void*)&int_cmd_code, sizeof(int));
1777 write(status_pipe_write, (void*)&status_data, sizeof(void*));
1780 * The parent always keeps the write file descriptor open, and
1781 * on HP and IBM, each write may not get flushed. Force it.
1783 util_fdsync(status_pipe_write);
1789 read_from_status_pipe(
1790 CG_STATUS *status_code_out,
1791 CG_SUBCOMMAND *cmd_code_out,
1792 void **status_data_out
1795 int return_value = 0;
1796 int int_status_code = 0;
1797 int int_cmd_code = 0;
1798 void *status_data = NULL;
1801 /* util_dprintf(2,"Data ready\n");*/
1802 if (status_pipe_write >= 0)
1804 util_fdsync(status_pipe_write);
1806 nread += read(status_pipe_read, (void *)&int_status_code, sizeof(int));
1807 nread += read(status_pipe_read, (void *)&int_cmd_code, sizeof(int));
1808 nread += read(status_pipe_read, (void *)&status_data, sizeof(void*));
1809 (*status_code_out) = (CG_STATUS)int_status_code;
1810 (*cmd_code_out) = (CG_SUBCOMMAND)int_cmd_code;
1811 (*status_data_out) = status_data;
1813 return_value = nread;
1816 /* The write end of the pipe is apparently closed */
1817 destroy_status_pipe();
1821 /*printf("rcv (fd:%d bytes:%d) read from pipe: %d %d %d\n",
1822 status_pipe_read, nread,
1823 (int)(*status_code_out),
1824 (int)(*cmd_code_out),
1825 (int)(*status_data_out));*/
1827 return return_value;
1832 * Tries to kill the process in a "friendly" way. Sends SIGTERM first,
1833 * waits 5 seconds, and then sends SIGKILL.
1835 * Returns >= 0 if successfully killed, <0 otherwise
1838 careful_kill_group(pid_t pgid)
1840 Bool killed = False;
1842 pid_t leader_pid = pgid;
1843 int child_status = 0;
1844 /* pid_t pid_done = INVALID_PID; */
1846 long kill_pgrp_id = (long)(-1 * pgid); /* negative pid = group id */
1848 /*util_dprintf(2, "careful_kill_group(%ld)\n", (long)pgid);*/
1853 kill(kill_pgrp_id, SIGTERM);
1854 for (waitcount= 0; (!killed) && (waitcount < 5); ++waitcount)
1856 if (kill(kill_pgrp_id, 0) == -1) /* sig 0 checks pid only */
1858 /* kill failed, so group doesn't exist, any more */
1868 * if SIGTERM was ignored, NUKE IT!
1872 kill(kill_pgrp_id, SIGKILL); /* can't ignore this, turkey! */
1873 for (waitcount= 0; (!killed) && (waitcount < 5); ++waitcount)
1875 if (kill(kill_pgrp_id, 0) == -1) /* sig 0 checks pid only */
1877 /* kill failed, so group doesn't exist, any more */
1887 /*util_dprintf(2,"%s: %ld\n", (killed? "Killed":"COULD NOT KILL"), (long)pgid);*/
1889 return killed? 0:-1;
1894 * projectName may be NULL (signifies no project)
1897 cgen_set_title(STRING projectName)
1900 strcpy(newTitle, "Code Generator ");
1901 if (projectName == NULL)
1903 strcat(newTitle, "(No Project)");
1907 sprintf(newTitle+strlen(newTitle), " - Project %s.bip",
1911 XtVaSetValues(XtParent(AB_cgen_win),
1920 * Sets the project dir: field to be the current directory
1921 * If dir is NULL, looks at CWD.
1924 cgen_set_project_dir(STRING dir)
1926 STRING newDir= NULL;
1927 XmString xmlabel= NULL;
1935 newDir= ab_get_cur_dir();
1937 xmlabel = XmStringCreateLocalized(newDir);
1938 XtVaSetValues(cur_dir_text,
1939 XmNlabelString, xmlabel,
1941 XmStringFree(xmlabel); xmlabel= NULL;
1947 cgen_obj_name_changed_cb(ObjEvAttChangeInfo evInfo)
1949 ABObj project= evInfo->obj;
1952 if ( (obj_is_project(project))
1953 && ((evInfo->atts & OBJEV_ATT_NAME) != 0)
1954 && (proj_get_project() == project)
1957 /* the project's name changed. Update the title bar */
1958 cgen_set_title(obj_get_name(project));
1968 /*util_dprintf(2, "GUI: aborting(%ld)\n", (long)actual_process_pgid);*/
1969 if ( (actual_process_pgid != INVALID_PID)
1970 && (abortingPID != actual_process_pgid) )
1972 /* the process still exists, and it is not in the
1973 * process of being aborted. Abort it!
1975 XtSetSensitive(abort_button, False);
1976 abortingPID = actual_process_pgid; /* do first!, so we know.. */
1977 careful_kill_group(abortingPID);
1978 XtSetSensitive(abort_button, True);
1981 if ( (actual_process_pgid == INVALID_PID)
1982 && (abortingPID == INVALID_PID) )
1984 /* There is no process to be aborted */
1993 * projectName may be NULL (signifies no project)
1996 set_props_proj_name(STRING projectName)
2000 if (projectName == NULL)
2002 strcpy(newProj, "(No Project)");
2006 sprintf(newProj, "%s.bip", projectName);
2009 XtVaSetValues(dtb_cgen_props_cgen_props_dlg.proj_name,
2010 XtVaTypedArg, XmNlabelString, XtRString,
2011 newProj, strlen(newProj)+1,
2018 * obj-callback: object name has changed - update Prop Dialog lists
2019 * Or project name has changed - update the Prop
2024 ObjEvAttChangeInfo info
2028 STRING mod_name = NULL;
2030 if (AB_cgen_prop_dialog != NULL)
2032 if (!obj_is_module(info->obj) && !obj_is_project(info->obj))
2037 if ( (obj_is_project(info->obj))
2038 && ((info->atts & OBJEV_ATT_NAME) != 0))
2040 /* the project's name changed. Update prop sheet proj_name */
2041 set_props_proj_name(obj_get_name(info->obj));
2045 mod_name = obj_get_name(info->obj);
2046 if (mod_name == NULL)
2049 XtVaGetValues(AB_cgen_prop_dialog, XmNuserData, &list, NULL);
2051 /* A new module was created and named */
2052 if (info->old_name != NULL)
2054 ui_list_replace_item(list, istr_string(info->old_name), mod_name);
2063 * obj-callback: object is being destroyed - remove from CGen prop
2068 ObjEvDestroyInfo info
2072 STRING mod_name = NULL;
2074 if (AB_cgen_prop_dialog != NULL)
2076 if (!obj_is_module(info->obj))
2079 mod_name = obj_get_name(info->obj);
2080 if (mod_name == NULL)
2083 XtVaGetValues(AB_cgen_prop_dialog, XmNuserData, &list, NULL);
2084 ui_list_delete_item(list, mod_name);
2091 * obj-callback: Called when a new project is opened.
2095 ObjEvUpdateInfo info
2100 if (AB_cgen_prop_dialog != NULL)
2102 if ( !obj_is_project(info->obj) &&
2103 !obj_is_module(info->obj)
2109 if (obj_is_project(info->obj))
2111 /* the project's name changed. Update prop sheet proj_name */
2112 set_props_proj_name(obj_get_name(info->obj));
2115 XtVaGetValues(AB_cgen_prop_dialog, XmNuserData, &list, NULL);
2116 XmListDeleteAllItems(list);
2117 cgenP_init_props_module_list(list);
2119 /* Initialize the selected modules lists */
2120 if (CodeGenOptions.module_list != NULL) /* the list that is applied */
2122 strlist_destroy(CodeGenOptions.module_list);
2123 CodeGenOptions.module_list = NULL;
2125 if (module_list != NULL) /* the list that reflects what
2126 * is currently selected */
2128 strlist_destroy(module_list);
2129 module_list = strlist_create();
2141 STRING request_dir = NULL;
2144 request_dir = ab_get_cur_dir();
2145 if (!util_strempty(request_dir))
2147 cmd_size = strlen("cd ") + strlen(request_dir) + 2;
2148 cmd = (STRING) XtMalloc(cmd_size);
2150 strcat(cmd, request_dir);
2152 DtTermSubprocSend(input_termWidget, (unsigned char*)cmd, strlen(cmd));
2159 do_user_action(CG_GOAL goal, CG_SUBCOMMAND cmd)
2161 int return_value = 0;
2162 int rc = 0; /* return code */
2163 BOOL doAction = TRUE;
2164 DTB_MODAL_ANSWER answer = DTB_ANSWER_NONE;
2165 ABObj project = proj_get_project();
2169 assert(cmd == CG_CMD_UNDEF); /* only startup implemented, here */
2171 /***** SEE IF cc IS ON THE PATH *****/
2173 if ((rc = check_path()) < 0)
2181 * See if we need to build the executable
2183 if (goal == CG_GOAL_RUN)
2185 char exeName[MAXPATHLEN+1];
2186 ABObj project = proj_get_project();
2187 STRING projName = NULL;
2188 if ((project != NULL) && ((projName = obj_get_name(project)) != NULL))
2190 sprintf(exeName, "./%s", projName);
2191 if (!util_file_exists(exeName))
2193 goal = CG_GOAL_UNDEF; /* can't run it - it don't exist! */
2194 dtb_cgen_win_no_exe_msg_initialize(
2195 &dtb_cgen_win_no_exe_msg);
2196 answer = dtb_show_modal_message(AB_cgen_win,
2197 &dtb_cgen_win_no_exe_msg,
2199 if (answer == DTB_ANSWER_ACTION1) /* Build It */
2201 goal = CG_GOAL_MAKE_AND_RUN;
2207 if (goal == CG_GOAL_UNDEF)
2214 /***** SEE IF THERE ARE UNSAVED EDITS *****/
2216 if ( (goal != CG_GOAL_RUN) && proj_check_unsaved_edits(project) )
2218 BOOL doSave = FALSE;
2220 if (all_files_exist(project))
2222 dtb_cgen_win_query_save_or_gen_old_msg_initialize(
2223 &dtb_cgen_win_query_save_or_gen_old_msg);
2224 answer = dtb_show_modal_message(AB_cgen_win,
2225 &dtb_cgen_win_query_save_or_gen_old_msg,
2229 case DTB_ANSWER_ACTION1: /* save */
2233 case DTB_ANSWER_ACTION2: /* gen old */
2243 dtb_cgen_win_query_save_or_abort_msg_initialize(
2244 &dtb_cgen_win_query_save_or_abort_msg);
2245 answer = dtb_show_modal_message(AB_cgen_win,
2246 &dtb_cgen_win_query_save_or_abort_msg,
2250 case DTB_ANSWER_ACTION1: /* save */
2262 doAction = FALSE; /* will be done by save_done_cb */
2263 proj_save_needed(save_done_cb);
2265 } /* proj_check_unsaved_edits() */
2269 exec_next_command(CG_CMD_UNDEF, 0);
2273 return return_value;
2278 save_done_cb(int status)
2285 exec_next_command(CG_CMD_UNDEF, 0);
2293 int return_value = 0;
2294 int rc = 0; /* return code */
2295 BOOL keepAsking = TRUE;
2299 static BOOL allowWarnUserAboutCc = TRUE;
2300 static STRING ccCmdList[] =
2303 "/opt/SUNWspro/bin/cc",
2305 "/usr/dist/local/exe/cc",
2308 if ((rc = check_path_to_cmd(ccCmdList, &allowWarnUserAboutCc)) < 0)
2316 static BOOL allowWarnUserAboutSh = TRUE;
2317 static STRING shCmdList[] =
2324 "/usr/dist/local/exe/sh",
2327 if ((rc = check_path_to_cmd(shCmdList, &allowWarnUserAboutSh)) < 0)
2335 static BOOL allowWarnUserAboutRm = TRUE;
2336 static STRING rmCmdList[] =
2343 if ((rc = check_path_to_cmd(rmCmdList, &allowWarnUserAboutRm)) < 0)
2349 if ((return_value >= 0) && (!keepAsking))
2354 return return_value;
2359 * Returns <0 if the user cancelled
2362 check_path_to_cmd(STRING *cmdList, BOOL *allowWarnUserInOut)
2364 #define allowWarnUser (*allowWarnUserInOut)
2365 int return_value = 0;
2366 BOOL userCancelled = FALSE;
2367 int rc = 0; /* return code */
2368 STRING foundCmd = NULL;
2369 DTB_MODAL_ANSWER answer = DTB_ANSWER_NONE;
2371 XmString xmMsg = NULL;
2372 STRING nopathCmd = NULL; /* cmd with no path */
2374 nopathCmd = strrchr(cmdList[0], '/');
2375 if (nopathCmd == NULL)
2377 nopathCmd = cmdList[0];
2382 if ((rc = select_command(cmdList, &foundCmd)) < 0)
2384 /* command not found, anywhere! */
2388 if (!util_streq(foundCmd, nopathCmd))
2391 char dirName[MAXPATHLEN+1];
2392 char *slashPtr = strrchr(foundCmd, '/');
2395 STRING oldPath = NULL;
2398 oldPath = cgenP_get_env_var("PATH");
2399 if (oldPath == NULL)
2404 if (slashPtr != NULL)
2406 dirNameLen = (int)(slashPtr - foundCmd);
2407 util_strncpy(dirName, foundCmd, dirNameLen+1);
2408 /*util_dprintf(2, "directory: '%s'\n", dirName);*/
2410 sprintf(buffer, catgets(Dtb_project_catd, 100, 52,
2411 "Your PATH does not contain the command %s.\n"
2412 "In order to access this command, may I append this\n"
2413 "directory to your path?:\n"
2416 nopathCmd, dirName);
2418 xmMsg = XmStringCreateLocalized(buffer);
2419 dtb_cgen_win_modify_path_msg_initialize(
2420 &dtb_cgen_win_modify_path_msg);
2421 answer = dtb_show_modal_message(AB_cgen_win,
2422 &dtb_cgen_win_modify_path_msg,
2424 XmStringFree(xmMsg); xmMsg = NULL;
2428 case DTB_ANSWER_ACTION1: /* Yes */
2429 sprintf(buffer, "%s:%s", oldPath, dirName);
2430 cgenP_put_env_var("PATH", buffer);
2433 case DTB_ANSWER_ACTION2: /* No */
2434 allowWarnUser = FALSE;
2437 case DTB_ANSWER_CANCEL:
2438 userCancelled = TRUE;
2445 if ((return_value >= 0) && userCancelled)
2449 return return_value;
2450 #undef allowWarnUser
2455 * Makes sure that all of the files for the project at least exist on
2459 all_files_exist(ABObj project)
2461 BOOL allFilesExist = TRUE;
2462 STRING fileName = NULL;
2464 ABObj module = NULL;
2466 if ( ((fileName= obj_get_file(project)) == NULL)
2467 || (!util_file_exists(fileName)) )
2469 allFilesExist = FALSE;
2470 abobj_set_save_needed(project, TRUE);
2473 for (trav_open(&trav, project, AB_TRAV_MODULES);
2474 ((module = trav_next(&trav)) != NULL); )
2476 if ( ((fileName= obj_get_file(module)) == NULL)
2477 || (!util_file_exists(fileName)) )
2479 allFilesExist = FALSE;
2480 abobj_set_save_needed(module, TRUE);
2485 return allFilesExist;
2490 cgenP_get_env_var(STRING varName)
2492 STRING value = NULL;
2494 if (user_env_vars != NULL)
2496 value = (STRING)strlist_get_str_data(user_env_vars, varName);
2500 value = getenv(varName);
2507 * Creates a duplicate of the value.
2510 cgenP_put_env_var(STRING varName, STRING varValue)
2513 STRING oldValue = NULL;
2514 STRING newValue = NULL;
2516 if (user_env_vars == NULL)
2518 user_env_vars = strlist_create();
2521 strIndex = strlist_get_str_index(user_env_vars, varName);
2524 strlist_get_str(user_env_vars, strIndex, (void **)&oldValue);
2525 if (oldValue != NULL)
2527 util_free(oldValue);
2529 strlist_remove_index(user_env_vars, strIndex); strIndex = -1;
2532 newValue = strdup(varValue);
2533 strlist_add_str(user_env_vars, varName, newValue);
2539 check_makefile(BOOL *continueOutPtr)
2541 static BOOL allowDestroyMakefile = TRUE;
2542 int return_value = 0;
2543 int rc = 0; /* return code */
2544 BOOL makefileExists = FALSE;
2545 BOOL makefileIsOK = FALSE;
2546 DTB_MODAL_ANSWER answer = DTB_ANSWER_NONE;
2548 BOOL doDestroyMakefile = FALSE;
2549 BOOL doGenMakefile = FALSE;
2550 BOOL makeStarted = FALSE;
2552 *continueOutPtr = TRUE;
2557 rc = cgenP_makefile_is_for_project("makefile", proj_get_project());
2560 makefileExists = makefileIsOK = TRUE;
2562 else if (rc == ERR_OPEN)
2564 makefileExists = FALSE;
2565 makefileIsOK = FALSE;
2569 makefileExists = TRUE;
2570 makefileIsOK = FALSE;
2581 if (!makefileExists)
2583 rc = cgenP_makefile_is_for_project("Makefile", proj_get_project());
2586 makefileExists = makefileIsOK = TRUE;
2588 else if (rc == ERR_OPEN)
2590 makefileExists = FALSE;
2591 makefileIsOK = FALSE;
2595 makefileExists = TRUE;
2596 makefileIsOK = FALSE;
2605 * Display a warning dialog
2607 if (!makefileExists)
2609 dtb_cgen_win_no_makefile_msg_initialize(&dtb_cgen_win_no_makefile_msg);
2610 answer = dtb_show_modal_message(AB_cgen_win,
2611 &dtb_cgen_win_no_makefile_msg,
2615 case DTB_ANSWER_ACTION1: /* Yes */
2616 doGenMakefile = TRUE;
2619 case DTB_ANSWER_ACTION2: /* No */
2620 doGenMakefile = FALSE;
2623 case DTB_ANSWER_CANCEL:
2624 doGenMakefile = FALSE;
2625 *continueOutPtr = FALSE;
2629 else if ((!makefileIsOK) && (allowDestroyMakefile))
2631 dtb_cgen_win_wrong_makefile_msg_initialize(
2632 &dtb_cgen_win_wrong_makefile_msg);
2633 answer = dtb_show_modal_message(AB_cgen_win,
2634 &dtb_cgen_win_wrong_makefile_msg,
2638 case DTB_ANSWER_ACTION1: /* Yes */
2639 doDestroyMakefile = TRUE;
2640 doGenMakefile = TRUE;
2643 case DTB_ANSWER_ACTION2: /* No */
2644 doGenMakefile = FALSE;
2647 case DTB_ANSWER_ACTION3: /* Never */
2648 doGenMakefile = FALSE;
2649 allowDestroyMakefile = FALSE;
2652 case DTB_ANSWER_CANCEL:
2653 doGenMakefile = FALSE;
2654 *continueOutPtr = FALSE;
2660 * Perform the actions specified by the user
2662 if (doDestroyMakefile)
2668 *continueOutPtr = FALSE; /* will restart when dtcodegen done */
2669 if ((rc = exec_generate_main()) >= 0)
2679 if (! (makeStarted || (*continueOutPtr)) )
2681 /* we're not doing anything */
2685 return return_value;
2692 destroy_links_to_file("makefile");
2693 destroy_links_to_file("Makefile");
2699 destroy_links_to_file(STRING fileName)
2701 int return_value = 0;
2702 struct stat doomedFileInfo;
2703 struct stat curFileInfo;
2705 struct dirent *dirEntry = NULL;
2706 StringList doomedFiles = strlist_create();
2710 strlist_add_str(doomedFiles, fileName, NULL);
2711 if (stat(fileName, &doomedFileInfo) != 0)
2719 return ERR_INTERNAL;
2722 while ((dirEntry= readdir(dir)) != NULL)
2724 if (stat(dirEntry->d_name, &curFileInfo) != 0)
2729 if ( (doomedFileInfo.st_dev == curFileInfo.st_dev)
2730 && (doomedFileInfo.st_ino == curFileInfo.st_ino) )
2732 /* files are the same! */
2733 strlist_add_str(doomedFiles, dirEntry->d_name, NULL);
2740 * We've built a list of all filenames in the current directory that
2741 * refer to the given file.
2743 numFiles = strlist_get_num_strs(doomedFiles);
2744 for (i = 0; i < numFiles; ++i)
2746 move_file_to_backup(strlist_get_str(doomedFiles, i, NULL));
2751 closedir(dir); dir = NULL;
2753 strlist_destroy(doomedFiles);
2754 return return_value;
2759 move_file_to_backup(STRING fileName)
2761 char bakNameBuf[MAXPATHLEN+1];
2762 int fileNameLen = strlen(fileName);
2764 if ((fileNameLen >= 4) && (strcmp(fileName+fileNameLen-4, ".BAK") == 0))
2766 /* Don't make a .BAK.BAK file */
2770 sprintf(bakNameBuf, "%s.BAK", fileName);
2772 return rename(fileName, bakNameBuf);
2777 cgenP_makefile_is_for_project(STRING fileName, ABObj project)
2779 int return_value = 0;
2780 FILE *makeFile = NULL;
2781 StringList genFileNames = strlist_create();
2782 ABObj module = NULL;
2786 assert((project == NULL) || obj_is_project(project));
2788 if (project == NULL)
2793 makeFile = util_fopen_locked(fileName, "r");
2794 if (makeFile == NULL)
2796 return_value = ERR_OPEN;
2801 * Create list of file names
2803 add_obj_file_name(genFileNames, project, NULL);
2804 for (trav_open(&trav, project, AB_TRAV_MODULES);
2805 (module = trav_next(&trav)) != NULL; )
2807 add_obj_file_name(genFileNames, module, "_ui");
2811 if (!strings_exist_in_file(genFileNames, makeFile))
2817 util_fclose(makeFile);
2818 strlist_destroy(genFileNames);
2819 return return_value;
2824 add_obj_file_name(StringList fileNames, ABObj obj, STRING suffix)
2826 STRING objName = NULL;
2827 char fileName[MAXPATHLEN+1];
2834 if ((objName = obj_get_name(obj)) == NULL)
2841 suffix = Util_empty_string;
2843 sprintf(fileName, "%s%s", objName, suffix);
2844 strlist_add_str(fileNames, fileName, NULL);
2850 strings_exist_in_file(StringList strings, FILE *file)
2852 #define fast_strneq(s1,s2,n) \
2853 (((*(s1)) == (*(s2))) && (strncmp(s1,s2,n) == 0))
2854 BOOL stringsExist = FALSE;
2855 STRING *stringsArray = NULL;
2856 int *stringsLenArray = NULL;
2857 int maxFileNameLen = 0;
2858 int curFileNameLen = 0;
2859 STRING curFileName = NULL;
2862 int numStringsFound = 0;
2864 int maxBufLen = sizeof(buf)-1;
2867 BOOL *stringExists = NULL;
2868 char *stringStart = NULL;
2871 numStrings = strlist_get_num_strs(strings);
2874 * Convert strings list to arrays, to avoid 750,000 calls to istr_string()
2876 stringsArray = (STRING*)util_malloc(numStrings * sizeof(STRING));
2877 stringsLenArray = (int*)util_malloc(numStrings * sizeof(int));
2878 stringExists = (BOOL*)util_malloc(numStrings * sizeof(BOOL));
2879 if ( (stringsArray == NULL)
2880 || (stringsLenArray == NULL)
2881 || (stringExists == NULL) )
2885 for (i = 0; i < numStrings; ++i)
2887 stringsArray[i] = strlist_get_str(strings, i, NULL);
2888 stringsLenArray[i] = strlen(stringsArray[i]);
2889 stringExists[i] = FALSE;
2894 * Determine the longest file name
2896 for (i = 0; i < numStrings; ++i)
2898 curFileName = stringsArray[i];
2899 curFileNameLen = stringsLenArray[i];
2900 maxFileNameLen = util_max(maxFileNameLen, curFileNameLen);
2902 assert(maxFileNameLen < sizeof(buf));
2908 bufLen = fread((void *)buf, 1, maxFileNameLen -1, file);
2909 while ((c = fgetc(file)) != EOF)
2911 if (bufLen >= maxBufLen)
2913 /* we've reached the end of the buffer */
2914 memmove(buf, buf + maxBufLen - maxFileNameLen, maxFileNameLen);
2915 bufLen = maxFileNameLen;
2919 for (i = 0; i < numStrings; ++i)
2921 if (stringExists[i])
2925 stringStart = buf + bufLen - stringsLenArray[i];
2926 if (fast_strneq(stringStart, stringsArray[i], stringsLenArray[i]))
2928 stringExists[i] = TRUE;
2929 if (++numStringsFound >= numStrings)
2932 * Instead of a loop-control variable that must get
2933 * checked on each iteration, we use a goto to speed
2934 * things up, dramatically.
2936 goto exit_file_loop;
2945 * See if they were all found
2947 stringsExist = TRUE;
2948 for (i = 0; i < numStrings; ++i)
2950 if (!stringExists[i])
2952 stringsExist = FALSE;
2958 util_dprintf(1, "Not in makefile: '%s'\n", stringsArray[i]);
2964 util_free(stringsArray);
2965 util_free(stringsLenArray);
2966 util_free(stringExists);
2967 return stringsExist;
2973 select_command(STRING *cmdList, STRING *cmdOutPtr)
2980 path = cgenP_get_env_var("PATH");
2982 for (i = 0; (cmdIndex < 0) && (cmdList[i] != NULL); ++i)
2984 if ((strlen(cmdList[i]) > 0) && (command_exists(cmdList[i], path)))
2993 *cmdOutPtr = cmdList[cmdIndex];
3000 command_exists(STRING cmd, STRING path)
3002 static uid_t euid = (uid_t)-1;
3003 static uid_t egid = (uid_t)-1;
3004 BOOL cmdExists = FALSE;
3005 char szCurrentPath[MAXPATHLEN+1];
3006 int iCurrentPathStart = -1;
3007 int iCurrentPathLen = -1;
3010 int iExeNameLen = strlen(cmd);
3011 BOOL moreDirs = FALSE;
3014 if (euid == (uid_t)-1)
3021 * Check for abolute path to command
3023 if ( (strncmp(cmd, "/", 1) == 0)
3024 || (strncmp(cmd, "./", 2) == 0)
3025 || (strncmp(cmd, "../", 3) == 0)
3028 /* an absolute path */
3029 cmdExists = path_is_executable(cmd, euid, egid);
3034 * Search path for command
3036 iCurrentPathStart = 0;
3037 iCurrentPathLen = 0;
3038 iPathLen = strlen(path);
3041 while ((!cmdExists) && (moreDirs))
3043 /* find beginning of dir name (skip ':') */
3044 while ( (iCurrentPathStart < iPathLen)
3045 && (path[iCurrentPathStart] == ':'))
3047 ++iCurrentPathStart; /* skip : */
3049 if (iCurrentPathStart >= iPathLen)
3055 /* find end of dir name */
3056 for (i= iCurrentPathStart; (i < iPathLen) && (path[i] != ':'); )
3060 iCurrentPathLen= i - iCurrentPathStart;
3062 /* make sure path to executable is not too long */
3063 if ((iCurrentPathLen + iExeNameLen + 2) > MAXPATHLEN)
3065 iCurrentPathLen= MAXPATHLEN - (iExeNameLen + 2);
3068 /* create a possible path to the executable */
3069 util_strncpy(szCurrentPath, &path[iCurrentPathStart],
3071 strcat(szCurrentPath, "/");
3072 strcat(szCurrentPath, cmd);
3074 /* see if the executable exists (and we can execute it) */
3075 if (path_is_executable(szCurrentPath, euid, egid))
3080 /* skip past the current directory name */
3081 iCurrentPathStart += iCurrentPathLen;
3082 } /* while !cmdExists */
3089 * returns False is path does not exist or is not executable
3098 Boolean bExecutable= False;
3101 /* util_dprintf(3, "path_is_executable(%s)\n", path); */
3102 if (stat(path, &sStat) == 0)
3104 Boolean bDetermined= False;
3108 if (!S_ISREG(sStat.st_mode))
3110 /* not a regular file */
3119 && ( ((sStat.st_mode & S_IXOTH) != 0)
3120 || ((sStat.st_mode & S_IXGRP) != 0)
3121 || ((sStat.st_mode & S_IXUSR) != 0) )
3131 if ( (((sStat.st_mode & S_IXOTH) != 0) )
3132 || (((sStat.st_mode & S_IXGRP) != 0) && (sStat.st_gid == egid))
3133 || (((sStat.st_mode & S_IXUSR) != 0) && (sStat.st_gid == euid))
3147 * This routine must be identical to that in src/abmf/obj_names.c. If
3148 * either this one or the other one is changed, copy the routine to the
3152 cvt_type_to_ident(STRING type, STRING identBuf, int identBufSize)
3157 int typeLen = util_strlen(type);
3158 int identMaxLen = identBufSize-1;
3159 int lastIdentChar = -1;
3160 BOOL lastTypeCharWasUpper = FALSE;
3163 (typeOff < typeLen) && (identOff < (identMaxLen-1)); ++typeOff)
3165 typeChar = type[typeOff];
3166 if (isupper(typeChar))
3168 if ( (lastIdentChar != '_')
3169 && (!lastTypeCharWasUpper)
3170 && (lastIdentChar != -1)
3173 lastIdentChar = identBuf[identOff++] = '_';
3175 if (identOff < (identMaxLen-1))
3177 lastIdentChar = identBuf[identOff++] = tolower(typeChar);
3179 lastTypeCharWasUpper = TRUE;
3183 lastIdentChar = identBuf[identOff++] = typeChar;
3184 lastTypeCharWasUpper = FALSE;
3187 identBuf[identOff] = 0;
3194 * util_fdsync() syncs the data and IO pending on an open file descriptor
3195 * out to the physical device, pipe, stream, or whatever.
3197 * REMIND: move this to libAButil
3203 extern int fsync(int fd); /* non-POSIX function */
3212 BOOL ok = FALSE; /* OK if either sync or datasync works */