(no subject)
- From: Craig May <craig may s2 enthdimension com au>
- To: gnome-devtools gnome org
- Subject: (no subject)
- Date: Sat, 9 Dec 2000 13:27:57 +0000
Added check for valid project directory (prev caused dump).
Added project directory selection dialog.
/* $Header: /cvs/gnome/gIDE/src/gI_project.c,v 1.17 2000/11/04 15:13:21 dirkvan Exp $ */
/* gIDE
* Copyright (C) 1998-2000 Steffen Kern
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "gide.h"
#include <dirent.h>
#include <sys/stat.h>
#include "gI_file.h"
#include "gI_compile_sets.h"
#include "gI_compile.h"
#include "gI_common.h"
#include "gI_window.h"
#include "gI_menus.h"
#include "gI_project.h"
#include "gI_project_window.h"
/* local prototypes */
static void project_open_file_in_editor(GtkWidget* widget, gchar* file);
static void project_add_new_file_to(GtkWidget* widget, gpointer);
static void close_project_files(gI_project* project);
/*static void project_open_file(GtkWidget* widget, gpointer data);*/
static gboolean is_compile_window_visible(GideDocument* doc);
static void project_add_to_current(gI_project* parent_project,
gI_project* project);
static gI_project* project_create(void);
static void project_destroy(gI_project* project);
static void project_open(void);
static void project_delete(void);
static void project_fill_prj_list(void);
static void project_delete_clicked(GnomeDialog* dlg, int button,
gpointer data);
static void project_open_clicked(GnomeDialog* dlg, int button,
gpointer data);
static gchar* project_get_includes(gI_project* project);
static gchar* project_get_libdirs(gI_project* project);
static gchar* project_get_libs(gI_project* project);
static gchar* project_get_makefile_name(gI_project* project);
static gchar* project_get_options(gI_project* project);
static void project_add_to_compile_window(GideDocument* document, gchar* buf);
static void project_objects_add(gI_project* project, gchar* exec_file);
static void project_compile_source(gI_project* project, gchar* c_filename,
GideDocument* document);
static void project_link(gI_project* project, gchar* c_filename,
GideDocument* document);
/* Additions for project dialog */
void project_open_dialog(GtkWidget* widget, gpointer data);
void project_set_dir(GtkFileSelection *selector, gpointer user_data);
/* globals */
static GtkWidget* project_open_window = NULL;
static GtkWidget* project_delete_window = NULL;
static GtkWidget* cb_open;
static GtkWidget* cb_close;
static GtkWidget* prj_list;
static GtkWidget* e_prjdir;
static GtkWidget* prj_open;
/*
static GtkWidget* cb_select;
*/
static GtkWidget* cb_delete;
static glong prj_selected = -1;
static gI_project* current_project = NULL;
static GtkWidget* root_tree = NULL;
static gchar* objects = NULL;
/*
* Create a new project structure
*/
static gI_project*
project_create(
void
)
{
glong i;
glong j;
gI_project* project;
project = g_malloc0(sizeof(gI_project));
for(i = 0; i < MAX_PROJECT_TARGETS; i++)
{
project->targets[i] = g_malloc0(sizeof(gI_target));
}
project->filename = NULL;
project->name = NULL;
project->version = NULL;
project->changelog = NULL;
project->prjroot = NULL;
project->prjfdir = NULL;
for(j = 0; j < MAX_PROJECT_TARGETS; j++)
{
for(i = 0; i < MAX_PROJECT_FILES; i++)
{
project->targets[j]->sources[i] = NULL;
project->targets[j]->build[i] = 0;
}
project->targets[j]->name = NULL;
project->targets[j]->sources_no = 0;
}
project->libs_no = 0;
for(i = 0; i < MAX_PROJECT_FILES; i++)
{
project->libs[i] = NULL;
}
project->cpar = NULL;
project->cinc = NULL;
project->lpar = NULL;
project->llib = NULL;
project->mtarget = NULL;
return project;
}
/*
* Destructor function to destroy project & deallocate mem etc.
*/
static void
project_destroy(
gI_project* project
)
{
glong i;
glong j;
g_assert(project);
if(project->filename)
{
g_free(project->filename);
}
if(project->name)
{
g_free(project->name);
}
if(project->version)
{
g_free(project->version);
}
if(project->changelog)
{
g_free(project->changelog);
}
if(project->prjroot)
{
g_free(project->prjroot);
}
if(project->prjfdir)
{
g_free(project->prjfdir);
}
for(j = 0; j < MAX_PROJECT_TARGETS; j++)
{
for(i = 0; i < project->targets[j]->sources_no; i++)
{
/* presumably, sources_no works */
g_assert(project->targets[j]->sources[i]);
g_free(project->targets[j]->sources[i]);
}
if(project->targets[j]->name)
{
g_free(project->targets[j]->name);
}
g_free(project->targets[j]);
}
for(j = 0; j < MAX_PROJECT_FILES && j < project->libs_no; j++)
{
/* presumably, libs_no works */
g_assert(project->libs[j]);
g_free(project->libs[j]);
}
if(project->cpar)
{
g_free(project->cpar);
}
if(project->cinc)
{
g_free(project->cinc);
}
if(project->lpar)
{
g_free(project->lpar);
}
if(project->llib)
{
g_free(project->llib);
}
gI_todo_list_destroy(project->todoList);
if(project->mtarget)
{
g_free(project->mtarget);
}
g_free(project);
}
/*
* Open and parse a project
*/
static void
project_open(
void
)
{
gchar* selected_project;
FILE* prjfile;
gchar* prjwp;
gchar buf[MAXLEN];
gchar key[64];
gchar arg[256];
gI_project* project;
glong i;
glong j = 0;
gchar* ptr;
GList* selection;
selection = GTK_CLIST(prj_list)->selection;
if(!selection)
{
return;
}
prj_selected = (gint)selection->data;
gtk_clist_get_text(GTK_CLIST(prj_list), prj_selected, 0, &selected_project);
prjwp = g_strdup_printf("%s/%s.prj", prj_path, selected_project);
prjfile = fopen(prjwp, "r");
if(!prjfile)
{
gI_error_dialog(_("Unable to open project file"));
g_free(prjwp);
return;
}
project = project_create();
project->filename = prjwp;
if(GTK_TOGGLE_BUTTON(cb_close)->active)
{
gI_file_close_all(NULL, NULL);
}
while(fgets(buf, sizeof(buf), prjfile))
{
g_strchug(buf);
if(buf[0] == ';' || buf[0] == '#' || buf[0] == '\0')
{
continue;
}
if(sscanf(buf, "%s %s\n", key, arg) != 2)
{
g_print("Unknown line in project file!\n");
g_print(buf);
continue;
}
if(!strcmp(key, "PROJECT:"))
{
project->name = g_strdup(arg);
}
else if(!strcmp(key, "VERSION:"))
{
project->version = g_strdup(arg);
}
else if(!strcmp(key, "CHANGELOG:"))
{
ptr = SK_GetBetween(buf, '!', '!');
project->changelog = g_strdup(ptr);
}
else if(!strcmp(key, "MTARGET:"))
{
ptr = SK_GetBetween(buf, '!', '!');
project->mtarget = g_strdup(ptr);
}
else if(!strcmp(key, "PRJROOT:"))
{
ptr = SK_GetBetween(buf, '!', '!');
project->prjroot = g_strdup(ptr);
}
else if(!strcmp(key, "PRJFDIR:"))
{
ptr = SK_GetBetween(buf, '!', '!');
project->prjfdir = g_strdup(ptr);
}
else if(!strcmp(key, "$TARGETS:"))
{
project->targets_no = atoi(arg);
for(i = 0; i < project->targets_no; i++)
{
fgets(buf, sizeof(buf), prjfile);
ptr = strchr(buf, '\n');
if(ptr)
{
*ptr = '\0';
}
project->targets[i]->name = g_strdup(buf);
}
fgets(buf, sizeof(buf), prjfile);
g_strchug(buf);
ptr = strchr(buf, '\n');
if(ptr)
{
*ptr = '\0';
}
if(strcmp(buf, "$END TARGETS"))
{
g_warning("Unfinished $TARGETS statement in project file\n");
}
}
else if(!strcmp(key, "$SOURCES:"))
{
project->targets[j]->sources_no = atoi(arg);
fgets(buf, sizeof(buf), prjfile);
j = atoi(buf);
for(i = 0; i < project->targets[j]->sources_no; i++)
{
fgets(buf, sizeof(buf), prjfile);
ptr = strchr(buf, '\n');
if(ptr)
{
*ptr = '\0';
}
if(GTK_TOGGLE_BUTTON(cb_open)->active)
{
project_open_file_in_editor(NULL, buf);
}
project->targets[j]->sources[i] = g_strdup(buf);
fgets(buf, sizeof(buf), prjfile);
project->targets[j]->build[i] = atoi(buf);
}
fgets(buf, sizeof(buf), prjfile);
g_strchug(buf);
ptr = strchr(buf, '\n');
if(ptr)
{
*ptr = '\0';
}
if(strcmp(buf, "$END SOURCES"))
{
g_warning("Unfinished $SOURCES statement in project file\n");
}
}
else if(!strcmp(key, "$LIBS:"))
{
project->libs_no = atoi(arg);
for(i = 0; i < project->libs_no; i++)
{
fgets(buf, sizeof(buf), prjfile);
if(feof(prjfile))
{
g_error("Unfinished statement in project file\n");
}
if(!strcmp(buf, "$END LIBS"))
{
/* something is going wrong */
g_warning("Can't find end of libs statement\n");
break;
}
ptr = strchr(buf, '\n');
if(ptr)
{
*ptr = '\0';
}
project->libs[i] = g_strdup(buf);
}
fgets(buf, sizeof(buf), prjfile);
g_strchug(buf);
ptr = strchr(buf, '\n');
if(ptr)
{
*ptr = '\0';
}
if(strcmp(buf, "$END LIBS"))
{
g_error("Unfinished $LIBS statement in project file\n");
}
}
else if(!strcmp(key, "CPAR:"))
{
strcpy(arg, SK_GetBetween(buf, '!', '!'));
project->cpar = g_strdup(arg);
}
else if(!strcmp(key, "CINC:"))
{
strcpy(arg, SK_GetBetween(buf, '!', '!'));
project->cinc = g_strdup(arg);
}
else if(!strcmp(key, "LPAR:"))
{
strcpy(arg, SK_GetBetween(buf, '!', '!' ));
project->lpar = g_strdup(arg);
}
else if(!strcmp(key, "LLIB:"))
{
strcpy(arg, SK_GetBetween(buf, '!', '!'));
project->llib = g_strdup(arg);
}
else if(!strcmp(key, "$Begin_Todo"))
{
project->todoList = gI_todo_list_read_from_file(prjfile,
"$End_Todo List");
}
else
{
g_print("Unknown line in project file!\n");
g_print(buf);
}
}
if(!project->todoList)
{
g_print("No todo list found");
project->todoList = gI_todo_list_create();
}
project_add_to_current(gI_project_get_current(), project);
current_project = project;
if(cfg->prjftree)
{
gtk_widget_show(main_window->tree_box);
gI_project_files_tree(main_window->tree_viewport, project);
}
prj_selected = -1;
}
/*
* Delete a project
*/
static void
project_delete(
void
)
{
gchar* selected_project;
gchar* prjwp;
FILE* prjfile;
gchar buf[MAXLEN];
gchar key[64];
gchar arg[64];
gchar* ptr;
glong i;
if(prj_selected == -1)
{
return;
}
gtk_clist_get_text(GTK_CLIST(prj_list), prj_selected, 0,
&selected_project);
prjwp = g_strdup_printf("%s/%s.prj", prj_path, selected_project);
if(GTK_TOGGLE_BUTTON(cb_delete)->active)
{
/* delete all source files as well */
prjfile = fopen(prjwp, "r");
if(!prjfile)
{
gI_error_dialog(_("Unable to open project file"));
g_free(prjwp);
return;
}
/* we read only the sources */
while(fgets(buf, MAXLEN, prjfile))
{
if(sscanf(buf, "%s %s", key, arg) != 2)
{
continue;
}
if(strcmp(key, "$SOURCES:"))
{
continue;
}
fgets(buf, sizeof(buf), prjfile);
for(i = 0; i < atoi(arg); i++)
{
fgets(buf, sizeof(buf), prjfile);
ptr = strchr(buf, '\n');
if(ptr)
{
*ptr = '\0';
}
remove(buf);
}
}
}
remove(prjwp);
g_free(prjwp);
gtk_clist_remove(GTK_CLIST(prj_list), prj_selected);
prj_selected = -1;
}
/*
* Callback when user clicks on project in project list
*/
static void
prj_list_select(
GtkWidget* widget,
gint row,
gint column,
GdkEventButton* bevent
)
{
if(!bevent)
{
return;
}
if(bevent->type == GDK_2BUTTON_PRESS || bevent->type == GDK_3BUTTON_PRESS)
{
prj_selected = row;
project_open();
prj_selected = -1;
/* close dialog box manually */
gnome_dialog_close(GNOME_DIALOG(project_open_window));
project_open_window = NULL;
gI_project_update_menu(main_window);
}
else
{
if(!GTK_CLIST(widget)->selection)
{
prj_selected = -1;
}
else
{
prj_selected = row;
}
}
}
/*
* Callback when user inputs a new path
*/
static void
prjdir_activated(
GtkWidget* widget,
gpointer data
)
{
gchar* path;
struct stat st;
path = gtk_entry_get_text(GTK_ENTRY(e_prjdir));
if(!path || isempty(path))
{
g_warning("Invalid Path.\n");
return;
}
stat(path, &st);
if(S_ISDIR(st.st_mode))
{
gtk_clist_clear(GTK_CLIST(prj_list));
strcpy(prj_path, path);
project_fill_prj_list();
}
else
{
g_warning("Invalid Path.\n");
return;
}
}
/*
* Add project to project list. Currently, just replace it - fixme when needed
*/
static void
project_add_to_current(
gI_project* parent_project,
gI_project* project
)
{
g_assert(project);
if(parent_project)
{
project_destroy(parent_project);
}
current_project = project;
}
static void
close_project_files(
gI_project* project
)
{
glong i;
glong j;
gchar source[MAXLEN];
for(i = 0; i < project->targets_no; i++)
{
for(j = 0; j < project->targets[i]->sources_no; j++)
{
if(isempty(project->prjroot))
{
g_snprintf(source, sizeof(source),
project->targets[i]->sources[j]);
}
else
{
g_snprintf(source, sizeof(source), "%s/%s", project->prjroot,
project->targets[i]->sources[j]);
}
if(check_file_open(source) && goto_file(source))
{
file_close(NULL, main_window);
}
}
}
}
static void
project_file_selected(
GtkWidget* widget,
GdkEventButton* event,
gchar* file
)
{
if(event->button == 3)
{
GnomeUIInfo popupmenu[] = {
GNOMEUIINFO_ITEM_NONE(_("Open file in editor"),
_("Open file in editor"), project_open_file_in_editor),
GNOMEUIINFO_ITEM_NONE(_("Add new file to project"),
_("Add new file to project"), project_add_new_file_to),
GNOMEUIINFO_ITEM_NONE(_("Remove file from project"),
_("Remove file from project"), gI_project_window_remove_file),
GNOMEUIINFO_END
};
gnome_popup_menu_do_popup_modal(gnome_popup_menu_new(popupmenu),
NULL, NULL, (GdkEventButton*)event, file);
}
else if(event->button == 1 && GTK_IS_TREE_ITEM(widget) &&
(event->type == GDK_2BUTTON_PRESS))
{
project_open_file_in_editor(NULL, file);
}
}
static void
project_open_file_in_editor(
GtkWidget* widget,
gchar* file
)
{
gchar* prjfile;
gI_project* project = gI_project_get_current();
if(!project)
{
return;
}
if(!isempty(project->prjroot))
{
prjfile = g_strdup_printf("%s/%s", project->prjroot, file);
}
else
{
prjfile = g_strdup(file);
}
if(!check_file_open(prjfile))
{
file_open_by_name(main_window, prjfile);
}
else
{
goto_file(prjfile);
}
g_free(prjfile);
}
static void
project_add_new_file_to(
GtkWidget* widget,
gpointer p
)
{
gI_ok_dialog(_("Not supported yet. Sorry..."));
}
static gboolean
is_compile_window_visible(
GideDocument* doc
)
{
gI_compile_window* compile_window;
compile_window = gI_document_get_compile_window(doc);
if(!doc || !compile_window ||
!compile_window->window ||
!compile_window->list ||
!GTK_WIDGET_VISIBLE(compile_window->window))
{
return FALSE;
}
return TRUE;
}
/*
* Get compiler options (cflags + includes)
* note: need to include compiler sets
* note: overlaps project_get_includes
*/
static gchar*
project_get_options(
gI_project* project
)
{
gchar** paths;
gchar* tmpstr;
gchar* options;
if(!isempty(project->cinc))
{
paths = g_strsplit(project->cinc, ":", 0);
tmpstr = g_strjoinv(" -I", paths);
g_strfreev(paths);
options = g_strconcat(project->cpar, " -I", tmpstr, NULL);
g_free(tmpstr);
}
else
{
if(!isempty(project->cpar))
{
options = g_strdup(project->cpar);
}
else
{
options = g_strdup("");
}
}
return options;
}
/*
* Add a string to the compile window
*/
static void
project_add_to_compile_window(
GideDocument* document,
gchar* buf
)
{
gchar* p;
gchar* item[1];
gI_compile_window* compile_window;
if(isempty(buf))
{
return;
}
compile_window = gI_document_get_compile_window(document);
/*
* a line splitter is needed here, but how long is one line???
*/
/*
* MAX_LINE_LENGTH is defined in gI_compile.h, currently it's set to 100.
* Maybe we should set dynamically depending on the current window width.
*/
if(strlen(buf) > MAX_LINE_LENGTH)
{
p = &buf[0];
while(strlen(p) > MAX_LINE_LENGTH)
{
gchar* e = &p[MAX_LINE_LENGTH];
gchar tmp[MAX_LINE_LENGTH + 1];
while(*e != ' ')
{
e--;
}
strncpy(tmp, p, e - p);
tmp[e - p] = '\0';
item[0] = tmp;
gtk_clist_append(GTK_CLIST(compile_window->list), item);
p = e + 1;
}
if(strlen(p) > 0)
{
item[0] = p;
gtk_clist_append(GTK_CLIST(compile_window->list), item);
}
}
else
{
item[0] = buf;
gtk_clist_append(GTK_CLIST(compile_window->list), item);
}
}
/*
* Add the object file to the objects array
*/
static void
project_objects_add(
gI_project* project,
gchar* exec_file
)
{
gchar* tmpstr;
if(isempty(project->prjroot))
{
if(objects)
{
tmpstr = g_strdup_printf("%s %s.o", objects, exec_file);
g_free(objects);
objects = tmpstr;
}
else
{
objects = g_strdup_printf("%s.o", exec_file);
}
}
else
{
if(objects)
{
tmpstr = g_strdup_printf("%s %s/%s.o", objects,
project->prjroot, exec_file);
g_free(objects);
objects = tmpstr;
}
else
{
objects = g_strdup_printf("%s/%s.o", project->prjroot,
exec_file);
}
}
}
/*
* Compile a source file to an object file
*/
static void
project_compile_source(
gI_project* project,
gchar* c_filename,
GideDocument* document
)
{
gchar* exec_file;
gchar* ptr;
gboolean cset_found = FALSE;
gchar* filename;
gchar* options = NULL;
gchar* exec_string;
gchar* tmpstr;
gchar* path = NULL;
gchar buf[STRLEN];
gchar* item[1];
FILE* file;
gI_comp_set* cset = NULL;
/* compile source files to objects */
if(c_filename == NULL || isempty(c_filename))
{
return;
}
exec_file = g_strdup(c_filename);
ptr = match_cset_fpat((cset = get_comp_set_from_filename(c_filename)),
exec_file);
if(!ptr)
{
cset_found = FALSE;
if(!(ptr = strstr(exec_file, ".c")))
{
gchar* str;
str = g_strdup_printf(_("Don't know how to compile %s"),
exec_file);
gI_error_dialog(str);
g_free(str);
g_free(exec_file);
return;
}
}
else
{
cset_found = TRUE;
}
/* only files, no targets */
if(c_filename[0] == '%')
{
g_free(exec_file);
return;
}
/* tmp filename */
filename = g_strdup_printf("%s/gide_bldprj.%d.%d",
cfg->tmpdir, (int)time(0), (int)getpid());
/* we change c_filename here!! */
if(ptr)
{
*ptr = '\0';
}
if(isempty(project->prjroot))
{
gchar* object;
object = g_strdup_printf("%s.o", exec_file);
if(get_last_mod(object) >= get_last_mod(c_filename))
{
if(objects)
{
tmpstr = g_strdup_printf("%s %s", objects, object);
g_free(objects);
objects = tmpstr;
g_free(object);
}
else
{
objects = object;
}
g_free(exec_file);
g_free(filename);
return;
}
g_free(object);
}
else
{
gchar* object;
gchar* source;
object = g_strdup_printf("%s/%s.o", project->prjroot, exec_file);
source = g_strdup_printf("%s/%s", project->prjroot, c_filename);
if(get_last_mod(object) >= get_last_mod(source))
{
if(objects)
{
tmpstr = g_strdup_printf("%s %s", objects, object);
g_free(objects);
objects = tmpstr;
g_free(object);
}
else
{
objects = object;
}
g_free(source);
g_free(exec_file);
g_free(filename);
return;
}
g_free(object);
g_free(source);
}
/* probably a bug: should use filename, not c_filename. but it works... */
/* change to working dir */
path = get_path(c_filename);
chdir(path);
g_free(path);
options = project_get_options(project);
/* real exec */
if(isempty(project->prjroot))
{
exec_string = g_strdup_printf(
"%s -c \"(%s %s -c %s -o %s.o 1>%s 2>&1 ; touch %s.done) &\"",
cfg->bash, cset_found ? cset->compiler : cfg->cc, options,
c_filename, exec_file, filename, filename);
}
else
{
exec_string = g_strdup_printf(
"%s -c \"(%s %s -c %s/%s -o %s/%s.o 1>%s 2>&1 ;"
" touch %s.done) &\"", cfg->bash,
cset_found ? cset->compiler : cfg->cc, options,
project->prjroot, c_filename, project->prjroot, exec_file,
filename, filename);
}
g_free(options);
options = NULL;
system(exec_string);
if(!is_compile_window_visible(document))
{
g_free(exec_file);
g_free(exec_string);
g_free(filename);
return;
}
/* Add the output of the compile to the compile window */
ptr = strstr(exec_string, "1>");
if(ptr)
{
*ptr = '\0';
}
ptr = strchr(exec_string, '(');
ptr++;
item[0] = ptr;
gtk_clist_append(GTK_CLIST(gI_document_get_compile_window(document)->list), item);
g_free(exec_string);
tmpstr = g_strdup_printf("%s.done", filename);
/* process gtk messages while the compile is busy */
while(!file_exist(tmpstr))
{
while(gtk_events_pending())
{
gtk_main_iteration();
}
}
/* remove .done file */
remove(tmpstr);
g_free(tmpstr);
file = fopen(filename, "r");
while(fgets(buf, sizeof(buf), file))
{
if(!is_compile_window_visible(document))
{
fclose(file);
g_free(exec_file);
g_free(filename);
return;
}
project_add_to_compile_window(document, buf);
}
fclose(file);
/* remove the tmp file */
remove(filename);
g_free(filename);
project_objects_add(project, exec_file);
g_free(exec_file);
if(!is_compile_window_visible(document))
{
return;
}
/* correct the scrolling */
gtk_clist_moveto(GTK_CLIST(gI_document_get_compile_window(document)->list),
GTK_CLIST(gI_document_get_compile_window(document)->list)->rows - 1, 0, 1.0, 0.0);
}
/*
* Link the project objects together
* note: does not use compile sets
*/
static void
project_link(
gI_project* project,
gchar* c_filename,
GideDocument* document
)
{
gchar* options;
gchar* exec_string;
gchar* tmpstr;
gchar* filename;
gchar* ptr = NULL;
gchar* item[1];
FILE* file;
gchar buf[STRLEN];
gchar* libdirs;
gchar* libs;
if(project->lpar)
{
options = g_strdup(project->lpar);
}
else
{
options = g_strdup("");
}
if(isempty(project->prjroot))
{
exec_string = g_strdup_printf("%s -c \"(%s %s -o %s ",
cfg->bash, cfg->cc, options, project->mtarget);
}
else
{
gchar* path;
path = get_path(project->mtarget);
if(path[0] == '\0')
{
exec_string = g_strdup_printf("%s -c \"(%s %s -o %s/%s ",
cfg->bash, cfg->cc, options, project->prjroot,
project->mtarget);
}
else
{
exec_string = g_strdup_printf("%s -c \"(%s %s -o %s ",
cfg->bash, cfg->cc, options, project->mtarget);
}
g_free(path);
}
tmpstr = g_strconcat(exec_string, objects, NULL);
g_free(exec_string);
exec_string = tmpstr;
libdirs = project_get_libdirs(project);
libs = project_get_libs(project);
tmpstr = g_strconcat(options, " ", libdirs, " ", libs, NULL);
g_free(options);
options = tmpstr;
g_free(libdirs);
g_free(libs);
/* tmp filename */
filename = g_strdup_printf("%s/gide_bldprj.%d.%d",
cfg->tmpdir, (int)time(0), (int)getpid());
tmpstr = g_strdup_printf("%s %s 1>%s 2>&1 ; touch %s.done) &\"",
exec_string, options, filename, filename);
g_free(exec_string);
exec_string = tmpstr;
g_free(options);
system(exec_string);
if(!is_compile_window_visible(document))
{
g_free(exec_string);
g_free(filename);
return;
}
/**/
ptr = strstr(exec_string, "1>");
if(ptr)
{
*ptr = '\0';
}
ptr = strchr(exec_string, '(');
ptr++;
item[0] = ptr;
gtk_clist_append(GTK_CLIST(gI_document_get_compile_window(document)->list), item);
g_free(exec_string);
tmpstr = g_strdup_printf("%s.done", filename);
while(!file_exist(tmpstr))
{
while(gtk_events_pending())
{
/* process gtk stuff */
gtk_main_iteration();
}
}
/* remove .done file */
remove(tmpstr);
g_free(tmpstr);
file = fopen(filename, "r");
while(fgets(buf, sizeof(buf), file))
{
if(!is_compile_window_visible(document))
{
g_free(filename);
return;
}
project_add_to_compile_window(document, buf);
}
if(!is_compile_window_visible(document))
{
g_free(filename);
return;
}
strcpy(buf, "Done.");
project_add_to_compile_window(document, buf);
/* remove temp file */
remove(filename);
g_free(filename);
if(!is_compile_window_visible(document))
{
return;
}
/* correct the scrolling */
gtk_clist_moveto(GTK_CLIST(gI_document_get_compile_window(document)->list),
GTK_CLIST(gI_document_get_compile_window(document)->list)->rows - 1, 0, 1.0, 0.0);
}
/*
* Fill the prj_list listbox with a list of current projects
*/
static void
project_fill_prj_list(
void
)
{
DIR* dir;
struct dirent* dirent;
gchar tmpstr[STRLEN];
gchar* ptr;
gchar* insrow[1];
dir = opendir(prj_path);
while((dirent = readdir(dir)))
{
if(strstr(dirent->d_name, ".prj"))
{
strncpy(tmpstr, dirent->d_name, STRLEN);
ptr = strstr(tmpstr, ".prj");
if(ptr)
{
if(strncmp(ptr, ".prj", 4))
{
continue;
}
*ptr = '\0';
}
insrow[0] = tmpstr;
gtk_clist_append(GTK_CLIST(prj_list), insrow);
}
}
closedir(dir);
}
/*
* Button callback for project delete
*/
static void
project_delete_clicked(
GnomeDialog* dlg,
int button,
gpointer data
)
{
switch(button)
{
case 0:
project_delete();
/* FALL THROUGH */
case 1:
gnome_dialog_close(dlg);
project_delete_window = NULL;
gI_project_update_menu(main_window);
break;
}
}
/*
* Button callback for project open
*/
static void
project_open_clicked(
GnomeDialog* dlg,
int button,
gpointer data
)
{
switch(button)
{
case 0:
project_open();
/* FALL THROUGH */
case 1:
gnome_dialog_close(dlg);
project_open_window = NULL;
gI_project_update_menu(main_window);
break;
}
}
/*
* Public functions
*/
/*
* Returns a pointer to the current project
*/
gI_project*
gI_project_get_current(
void
)
{
return current_project;
}
/*
* Create a new project
*/
void
gI_project_new(
GtkWidget* widget,
gpointer data
)
{
gI_project* project;
project = project_create();
project->todoList = gI_todo_list_create();
project_add_to_current(gI_project_get_current(), project);
gI_project_window_create(project, GI_PW_NEW);
}
/*
* Open an existing project
*/
void
gI_project_open(
GtkWidget* widget,
gpointer data
)
{
GtkBox* vbox;
GtkWidget* hbox;
GtkWidget* frame;
GtkWidget* frame_vbox;
GtkWidget* scrolled;
GtkWidget* button_open;
if(project_open_window)
{
return;
}
project_open_window = gnome_dialog_new(_("Open project"),
_("Open"), GNOME_STOCK_BUTTON_CLOSE, NULL);
gnome_dialog_set_parent(GNOME_DIALOG(project_open_window),
GTK_WINDOW(main_window));
vbox = GTK_BOX(GNOME_DIALOG(project_open_window)->vbox);
frame = gtk_frame_new(_("Existing projects"));
gtk_box_pack_start(vbox, frame, TRUE, TRUE, 5);
scrolled = gtk_scrolled_window_new(NULL, NULL);
gtk_container_add(GTK_CONTAINER(frame), scrolled);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
prj_list = gtk_clist_new(1);
gtk_container_add(GTK_CONTAINER(scrolled), prj_list);
gtk_widget_set_usize(scrolled, 150, 75);
gtk_signal_connect(GTK_OBJECT(prj_list), "select_row",
GTK_SIGNAL_FUNC(prj_list_select), NULL);
gtk_signal_connect(GTK_OBJECT(prj_list),"unselect_row",
GTK_SIGNAL_FUNC(prj_list_select), NULL);
gtk_box_pack_start(vbox, gtk_hseparator_new(), FALSE, TRUE, 5);
frame = gtk_frame_new(_("Options"));
gtk_box_pack_start(vbox, frame, FALSE, TRUE, 5);
frame_vbox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(frame), frame_vbox);
cb_open = gtk_check_button_new_with_label(_("Open all project files"));
gtk_box_pack_start(GTK_BOX(frame_vbox), cb_open, FALSE, TRUE, 0);
cb_close = gtk_check_button_new_with_label(_("Close all other files"));
gtk_box_pack_start(GTK_BOX(frame_vbox), cb_close, FALSE, TRUE, 0);
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(frame_vbox), hbox, FALSE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("Directory:")), FALSE,
TRUE, 5);
e_prjdir = gtk_entry_new_with_max_length(255);
gtk_box_pack_start(GTK_BOX(hbox), e_prjdir, TRUE, TRUE, 1);
gtk_signal_connect(GTK_OBJECT(e_prjdir), "activate",
GTK_SIGNAL_FUNC(prjdir_activated), NULL);
button_open = gtk_button_new_with_label (_("..."));
gtk_widget_ref (button_open);
gtk_object_set_data_full (GTK_OBJECT (project_open_window), "button_open", button_open,
(GtkDestroyNotify) gtk_widget_unref);
gtk_widget_show (button_open);
gtk_box_pack_start (GTK_BOX (hbox), button_open, FALSE, FALSE, 0);
gtk_widget_set_usize (button_open, -2, 19);
gtk_signal_connect(GTK_OBJECT(button_open), "clicked",
GTK_SIGNAL_FUNC(project_open_dialog), NULL);
project_fill_prj_list();
gtk_entry_set_text(GTK_ENTRY(e_prjdir), prj_path);
gtk_widget_show_all(GTK_WIDGET(vbox));
gnome_dialog_set_default(GNOME_DIALOG(project_open_window), 0);
gtk_signal_connect(GTK_OBJECT(project_open_window), "clicked",
GTK_SIGNAL_FUNC(project_open_clicked), NULL);
gtk_widget_show(project_open_window);
}
/*
* Open dialog handler
*/
void project_set_dir(GtkFileSelection *selector, gpointer user_data)
{
gtk_entry_set_text(GTK_ENTRY(e_prjdir), gtk_file_selection_get_filename(GTK_FILE_SELECTION(prj_open)));
prjdir_activated(NULL, NULL);
}
/*
* Show open dialog
*/
void
project_open_dialog(
GtkWidget* widget,
gpointer data)
{
prj_open = gtk_file_selection_new("Select directory.");
gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION(prj_open)->ok_button),
"clicked", GTK_SIGNAL_FUNC (project_set_dir), NULL);
gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION(prj_open)->ok_button),
"clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) prj_open);
gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION(prj_open)->cancel_button),
"clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), (gpointer) prj_open);
gtk_widget_show (prj_open);
}
/*
* Delete a project
*/
void
gI_project_delete(
GtkWidget* widget,
gpointer data
)
{
GtkBox* vbox;
GtkWidget* frame;
GtkWidget* frame_vbox;
if(project_delete_window)
{
return;
}
project_delete_window = gnome_dialog_new(_("Delete project"),
_("Delete"), GNOME_STOCK_BUTTON_CANCEL, NULL);
gnome_dialog_set_parent(GNOME_DIALOG(project_delete_window),
GTK_WINDOW(main_window));
vbox = GTK_BOX(GNOME_DIALOG(project_delete_window)->vbox);
frame = gtk_frame_new(_("Existing projects"));
gtk_box_pack_start(vbox, frame, TRUE, TRUE, 5);
prj_list = gtk_clist_new(1);
gtk_container_add(GTK_CONTAINER(frame), prj_list);
gtk_widget_set_usize(prj_list, 150, 75);
gtk_signal_connect(GTK_OBJECT(prj_list), "select_row",
GTK_SIGNAL_FUNC(prj_list_select), NULL);
gtk_signal_connect(GTK_OBJECT(prj_list), "unselect_row",
GTK_SIGNAL_FUNC(prj_list_select), NULL);
gtk_box_pack_start(vbox, gtk_hseparator_new(), FALSE, TRUE, 5);
frame = gtk_frame_new(_("Options"));
gtk_box_pack_start(vbox, frame, FALSE, TRUE, 5);
frame_vbox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(frame), frame_vbox);
cb_delete = gtk_check_button_new_with_label(_("Delete all project files"));
gtk_box_pack_start(GTK_BOX(frame_vbox), cb_delete, FALSE, TRUE, 0);
project_fill_prj_list();
gtk_widget_show_all(GTK_WIDGET(vbox));
gnome_dialog_set_default(GNOME_DIALOG(project_delete_window), 0);
gtk_signal_connect(GTK_OBJECT(project_delete_window), "clicked",
GTK_SIGNAL_FUNC(project_delete_clicked), NULL);
gtk_widget_show(project_delete_window);
gI_project_update_menu(main_window);
}
/*
* Close the current project
*/
void
gI_project_close(
GtkWidget* widget,
gpointer data
)
{
gI_project* project;
project = gI_project_get_current();
if(!project)
{
return;
}
if(root_tree)
{
gtk_widget_destroy(root_tree);
root_tree = NULL;
}
gtk_widget_hide(main_window->tree_box);
gtk_widget_queue_resize(GTK_WIDGET(main_window));
close_project_files(project);
project_destroy(project);
gtk_paned_set_position(GTK_PANED(main_window->hpane), 0);
project = NULL;
current_project = NULL;
gI_project_update_menu(main_window);
}
/*
* Edit the current project
*/
void
gI_project_edit(
GtkWidget* widget,
gpointer data
)
{
gI_project* project;
project = gI_project_get_current();
if(!project)
{
return;
}
gI_project_window_create(project, GI_PW_EDIT);
}
/*
* Extract the include paths from a project (in -I... format)
* note: should add paths from compile set
*/
static gchar*
project_get_includes(
gI_project* project
)
{
gchar** paths;
gchar* tmpstr;
gchar* includes;
if(!isempty(project->cinc))
{
paths = g_strsplit(project->cinc, ":", 0);
tmpstr = g_strjoinv(" -I", paths);
g_strfreev(paths);
includes = g_strconcat("-I", tmpstr, NULL);
g_free(tmpstr);
}
else
{
includes = g_strdup("");
}
return includes;
}
/*
* Extract the library paths from a project (in -L... format)
* note: should add paths from compile set
*/
static gchar*
project_get_libdirs(
gI_project* project
)
{
gchar** paths;
gchar* tmpstr;
gchar* libdirs;
if(!isempty(project->llib))
{
paths = g_strsplit(project->llib, ":", 0);
tmpstr = g_strjoinv(" -L", paths);
g_strfreev(paths);
libdirs = g_strconcat("-L", tmpstr, NULL);
g_free(tmpstr);
}
else
{
libdirs = g_strdup("");
}
return libdirs;
}
/*
* Extract the libraries from a project (in -l... format)
* note: should add libraries from compile set
*/
static gchar*
project_get_libs(
gI_project* project
)
{
gchar* libs;
gchar* tmpstr;
gint i;
libs = g_strdup("");
if(project->libs_no > 0)
{
for(i = 0; i < project->libs_no; i++)
{
tmpstr = g_strdup_printf("%s -l%s", libs, project->libs[i]);
g_free(libs);
libs = tmpstr;
}
}
return libs;
}
/*
* Extract the makefile name from a project (including full path)
*/
static gchar*
project_get_makefile_name(
gI_project* project
)
{
gchar* mf;
if(!isempty(project->version))
{
mf = g_strconcat(project->prjroot, "/Makefile", ".", project->name,
"-", project->version, NULL);
}
else
{
mf = g_strconcat(project->prjroot, "/Makefile", ".", project->name,
NULL);
}
return mf;
}
/*
* Create a makefile for the current project
*/
void
gI_project_create_makefile(
GtkWidget* widget,
gpointer data
)
{
FILE* makefile;
gI_project* project;
glong i;
glong j;
gchar* tmpstr;
gchar* ptr;
gchar* libdirs;
gchar* libs;
gchar* includes;
gchar* mf;
project = gI_project_get_current();
if(project == NULL)
{
gI_error_dialog(_("Can't create a makefile for an empty project"));
return;
}
if(isempty(project->name))
{
gI_error_dialog(_("Project doesn't have a name"));
return;
}
mf = project_get_makefile_name(project);
if(file_exist(mf))
{
if(gI_ask_dialog(_("The makefile already exists.\nDo you want to "
"overwrite it?")) != 0)
{
g_free(mf);
return;
}
}
makefile = fopen(mf, "w");
if(!makefile)
{
g_free(mf);
gI_error_dialog(_("Unable to create or write to the makefile"));
return;
}
g_free(mf);
includes = project_get_includes(project);
libdirs = project_get_libdirs(project);
libs = project_get_libs(project);
fprintf(makefile, "# Makefile for project '%s' generated by gIDE %s\n",
project->name, VERSION);
fprintf(makefile, "CC=%s\n", cfg->cc);
fprintf(makefile, "LD=%s\n", cfg->cc);
fprintf(makefile, "RM=%s\n", "rm");
fprintf(makefile, "INSTALL=%s\n\n", "install");
fprintf(makefile, "INCLUDES=%s\n", includes);
fprintf(makefile, "LIB_DIRS=%s\n", libdirs);
fprintf(makefile, "LIBS=%s\n", libs);
fprintf(makefile, "LDFLAGS=%s\n", project->lpar);
fprintf(makefile, "CFLAGS=%s\n\n", project->cpar);
g_free(includes);
g_free(libdirs);
g_free(libs);
fprintf(makefile, "COMPILE=$(CC) $(INCLUDES) $(CFLAGS) -c $<\n");
fprintf(makefile, "LINK=$(LD) $(LDFLAGS) -o $(MTARGET) $(OBJECTS) "
"$(LIB_DIRS) $(LIBS)\n\n");
/***
fprintf(makefile, "all:");
for(i = 0; i < project->targets_no; i++)
{
fprintf(makefile, " %s", project->targets[i]->name);
}
fprintf(makefile, "\n");
***/
/***
for(i = 0; i < project->targets_no; i++)
{
fprintf(makefile, "%s:", project->targets[i]->name);
for(j = 0; j < project->targets[i]->sources_no; j++)
{
fprintf(makefile, " %s", project->targets[i]->sources[j]);
}
fprintf(makefile, "\n\n");
}
***/
fprintf(makefile, "MTARGET=%s\n", project->mtarget);
fprintf(makefile, "OBJECTS=");
for(i = 0; i < project->targets_no; i++)
{
for(j = 0; j < project->targets[i]->sources_no; j++)
{
if(!project->targets[i]->build[j])
{
continue;
}
tmpstr = strdup(project->targets[i]->sources[j]);
if((ptr = strstr(tmpstr, ".c")))
{
*ptr = '\0';
fprintf(makefile, " %s.o", g_basename(tmpstr));
}
g_free(tmpstr);
}
}
fprintf(makefile, "\n\n");
fprintf(makefile, "all: %s\n\n", project->mtarget);
fprintf(makefile, "%s: $(OBJECTS)\n", project->mtarget);
fprintf(makefile, "\t$(LINK)\n\n");
for(i = 0; i < project->targets_no; i++)
{
for(j = 0; j < project->targets[i]->sources_no; j++)
{
if(!project->targets[i]->build[j])
{
continue;
}
tmpstr = g_strdup(project->targets[i]->sources[j]);
if((ptr = strstr(tmpstr, ".c")))
{
*ptr = '\0';
fprintf(makefile, "%s.o:", g_basename(tmpstr));
fprintf(makefile, " %s\n",
g_basename(project->targets[i]->sources[j]));
fprintf(makefile, "\t$(COMPILE)\n\n");
}
g_free(tmpstr);
}
}
fprintf(makefile, "\n\n");
fprintf(makefile, "install:\n\t$(INSTALL) -m 755 %s /usr/local/bin\n\n",
project->mtarget);
fprintf(makefile, "clean:\n\t$(RM) -f *~ core *.o %s\n", project->mtarget);
fprintf(makefile, "\n\n");
fclose(makefile);
gI_ok_dialog(_("Makefile created successfully"));
}
/*
* Create a tree view for the project files
*/
void
gI_project_files_tree(
GtkWidget* container,
gI_project* project
)
{
GtkWidget* root_item;
GtkWidget* sub_tree;
GtkWidget* sub_item;
GList* con_list;
glong i;
glong j;
if(container == NULL)
{
return;
}
if(root_tree != NULL)
{
con_list = gtk_container_children(GTK_CONTAINER(container));
if(con_list)
{
gtk_container_remove(GTK_CONTAINER(container), root_tree);
}
}
gtk_paned_set_position(GTK_PANED(main_window->hpane), -1);
root_tree = gtk_tree_new();
gtk_container_add(GTK_CONTAINER(container), root_tree);
gtk_widget_show(root_tree);
root_item = gtk_tree_item_new_with_label(project->name);
gtk_tree_append(GTK_TREE(root_tree), root_item);
for(j = 0; j < project->targets_no; j++)
{
sub_tree = gtk_tree_new();
gtk_tree_item_set_subtree(GTK_TREE_ITEM(root_item), sub_tree);
gtk_widget_show(sub_tree);
for(i = 0; i < project->targets[j]->sources_no; i++)
{
sub_item = gtk_tree_item_new_with_label(
project->targets[j]->sources[i]);
gtk_signal_connect(GTK_OBJECT(sub_item), "button_press_event",
GTK_SIGNAL_FUNC(project_file_selected),
project->targets[j]->sources[i]);
gtk_tree_append(GTK_TREE(sub_tree), sub_item);
gtk_widget_show(sub_item);
}
}
gtk_tree_item_expand(GTK_TREE_ITEM(root_item));
gtk_widget_show(root_item);
}
/*
* Build the currently open project
*/
void
gI_project_build(
GtkWidget* widget,
gpointer data
)
{
glong i;
glong j;
GideDocument* current;
gI_project* project;
static gboolean build_is_running = FALSE;
if(build_is_running)
{
gI_error_dialog(_("There's already a build running"));
return;
}
build_is_running = TRUE;
gI_menus_set_sensitive(main_window, "/Project/Build Project", FALSE);
/* in fact, we don't need the curren document here, but w/ it, we can use
the old functions */
current = gI_window_get_current_doc(main_window);
if(!current)
{
current = GIDE_DOCUMENT(gI_document_new());
}
project = gI_project_get_current();
if(project != NULL)
{
if(gI_document_get_compile_window(current) == NULL)
{
gI_compile_window* compile_window;
compile_window = gI_compile_window_new(
_("Compile Window"));
gI_document_set_compile_window(current, compile_window);
gtk_signal_connect(GTK_OBJECT(compile_window->window),
"destroy", GTK_SIGNAL_FUNC(gI_compile_window_destroy),
current);
gtk_signal_connect(
GTK_OBJECT(compile_window->close_button), "clicked",
GTK_SIGNAL_FUNC(gI_compile_window_destroy), current);
gtk_widget_show(compile_window->window);
}
/* init. */
if(objects != NULL)
{
g_free(objects);
objects = NULL;
}
show_compiling(current);
/* compile all project files */
for(i = 0; i < project->targets_no; i++)
{
for(j = 0; j < project->targets[i]->sources_no; j++)
{
/* build the source? */
if(project->targets[i]->build[j])
{
project_compile_source(project,
project->targets[i]->sources[j], current);
}
}
}
project_link(project, project->mtarget, current);
if(objects != NULL)
{
g_free(objects);
objects = NULL;
}
if(!is_compile_window_visible(current))
{
build_is_running = FALSE;
gI_menus_set_sensitive(main_window, "/Project/Build Project", TRUE);
return;
}
gtk_widget_destroy(gI_document_get_compile_window(current)->comp_dialog);
gI_document_get_compile_window(current)->comp_dialog = NULL;
}
build_is_running = FALSE;
gI_menus_set_sensitive(main_window, "/Project/Build Project", TRUE);
}
/*
* Update the menu sensitivity
*/
void
gI_project_update_menu(
GideWindow* window
)
{
if(gI_project_get_current() != NULL)
{
gI_menus_set_sensitive(window, "/Project/Open Project", FALSE);
gI_menus_set_sensitive(window, "/Project/Close Project", TRUE);
gI_menus_set_sensitive(window, "/Project/Build Project", TRUE);
gI_menus_set_sensitive(window, "/Project/Create Makefile", TRUE);
}
else
{
if(project_open_window)
{
gI_menus_set_sensitive(window, "/Project/Open Project", FALSE);
}
else
{
gI_menus_set_sensitive(window, "/Project/Open Project", TRUE);
}
gI_menus_set_sensitive(window, "/Project/Close Project", FALSE);
gI_menus_set_sensitive(window, "/Project/Build Project", FALSE);
gI_menus_set_sensitive(window, "/Project/Create Makefile", FALSE);
}
gI_menus_set_sensitive(window, "/Project/Delete Project",
project_delete_window == NULL);
gI_project_window_update_menu(window);
}
[Date Prev][
Date Next] [Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]