diff options
Diffstat (limited to 'fluid/Project.cxx')
| -rw-r--r-- | fluid/Project.cxx | 325 |
1 files changed, 223 insertions, 102 deletions
diff --git a/fluid/Project.cxx b/fluid/Project.cxx index 4545530a6..51cbbde27 100644 --- a/fluid/Project.cxx +++ b/fluid/Project.cxx @@ -15,34 +15,66 @@ // #include <errno.h> // strerror(errno) +#include <stdlib.h> // free, malloc +#include <string.h> // strdup, strlen, strcmp + #include "Project.h" +#include "Fluid.h" #include "io/String_Writer.h" #include "nodes/Node.h" #include "panels/settings_panel.h" #include "panels/codeview_panel.h" +#include "tools/filename.h" -using namespace fld; +#include <FL/fl_ask.H> +#include <FL/fl_utf8.h> // ---- project settings /** Initialize a new project. */ -Project::Project() { +fld::Project::Project() + : undo(*this), + tree(*this), + i18n(*this), + include_H_from_C(1), + use_FL_COMMAND(0), + utf8_in_src(0), + avoid_early_includes(0), + header_file_set(0), + code_file_set(0), + write_mergeback_data(0), + proj_filename(0), + header_file_name_(0), + code_file_name_(0), + include_guard_(0), + in_project_dir(0), + modflag(0), + modflag_c(0), + layout(app::default_layout_preset) +{ + app_work_dir_[0] = '\0'; + set_header_file_name(".h"); + set_code_file_name(".cxx"); + set_include_guard(""); } /** Clear all project resources. - Not implemented. */ -Project::~Project() { +fld::Project::~Project() { + if (header_file_name_) free(header_file_name_); + if (code_file_name_) free(code_file_name_); + if (include_guard_) free(include_guard_); + if (proj_filename) free((void*)proj_filename); } /** Reset all project setting to create a new empty project. */ -void Project::reset() { +void fld::Project::reset() { ::delete_all(); i18n.reset(); @@ -52,133 +84,207 @@ void Project::reset() { avoid_early_includes = 0; header_file_set = 0; code_file_set = 0; - header_file_name = ".h"; - code_file_name = ".cxx"; - include_guard = ""; + set_header_file_name(".h"); + set_code_file_name(".cxx"); + set_include_guard(""); write_mergeback_data = 0; } /** Tell the project and i18n tab of the settings dialog to refresh themselves. */ -void Project::update_settings_dialog() { +void fld::Project::update_settings_dialog() { if (settings_window) { w_settings_project_tab->do_callback(w_settings_project_tab, LOAD); w_settings_i18n_tab->do_callback(w_settings_i18n_tab, LOAD); } } +// Setters for string members + +void fld::Project::set_header_file_name(const char *name) { + if (header_file_name_) free(header_file_name_); + header_file_name_ = name ? strdup(name) : 0; +} + +void fld::Project::set_code_file_name(const char *name) { + if (code_file_name_) free(code_file_name_); + code_file_name_ = name ? strdup(name) : 0; +} + +void fld::Project::set_include_guard(const char *guard) { + if (include_guard_) free(include_guard_); + include_guard_ = guard ? strdup(guard) : 0; +} + /** Get the absolute path of the project file, for example `/Users/matt/dev/`. - \return the path ending in '/' + \param[out] buf buffer to store result (ends with '/') + \param[in] bufsize size of buffer */ -std::string Project::projectfile_path() const { - if (!proj_filename) return std::string{}; - return end_with_slash(fl_filename_absolute_str(fl_filename_path_str(proj_filename), Fluid.launch_path())); +void fld::Project::projectfile_path(char *buf, int bufsize) const { + buf[0] = '\0'; + if (!proj_filename) return; + + char path[FL_PATH_MAX]; + fl_filename_path(path, FL_PATH_MAX, proj_filename); + + char abs_path[FL_PATH_MAX]; + fl_filename_absolute(abs_path, FL_PATH_MAX, path, Fluid.launch_path()); + + fld_end_with_slash(buf, bufsize, abs_path); } /** Get the project file name including extension, for example `test.fl`. \return the file name without path */ -std::string Project::projectfile_name() const { - if (!proj_filename) return std::string{}; +const char *fld::Project::projectfile_name() const { + if (!proj_filename) return 0; return fl_filename_name(proj_filename); } /** Get the absolute path of the generated C++ code file, for example `/Users/matt/dev/src/`. - \return the path ending in '/' + \param[out] buf buffer to store result (ends with '/') + \param[in] bufsize size of buffer */ -std::string Project::codefile_path() const { - std::string path = fl_filename_path_str(code_file_name); - if (Fluid.batch_mode) - return end_with_slash(fl_filename_absolute_str(path, Fluid.launch_path())); - else - return end_with_slash(fl_filename_absolute_str(path, projectfile_path())); +void fld::Project::codefile_path(char *buf, int bufsize) const { + buf[0] = '\0'; + + char path[FL_PATH_MAX]; + fl_filename_path(path, FL_PATH_MAX, code_file_name_); + + char abs_path[FL_PATH_MAX]; + if (Fluid.batch_mode) { + fl_filename_absolute(abs_path, FL_PATH_MAX, path, Fluid.launch_path()); + } else { + char proj_path[FL_PATH_MAX]; + projectfile_path(proj_path, FL_PATH_MAX); + fl_filename_absolute(abs_path, FL_PATH_MAX, path, proj_path); + } + + fld_end_with_slash(buf, bufsize, abs_path); } /** Get the generated C++ code file name including extension, for example `test.cxx`. - \return the file name without path + \param[out] buf buffer to store result + \param[in] bufsize size of buffer */ -std::string Project::codefile_name() const { - std::string name = fl_filename_name_str(code_file_name); - if (name.empty()) { - if (!proj_filename) return std::string{}; - return fl_filename_setext_str(fl_filename_name(proj_filename), ".cxx"); +void fld::Project::codefile_name(char *buf, int bufsize) const { + buf[0] = '\0'; + + const char *name = fl_filename_name(code_file_name_); + if (!name || !*name) { + // No name specified, use project filename with .cxx extension + if (!proj_filename) return; + strlcpy(buf, fl_filename_name(proj_filename), bufsize); + fl_filename_setext(buf, bufsize, ".cxx"); } else if (name[0] == '.') { - if (!proj_filename) return std::string{}; - return fl_filename_setext_str(fl_filename_name(proj_filename), code_file_name); + // Only extension specified, use project filename with this extension + if (!proj_filename) return; + strlcpy(buf, fl_filename_name(proj_filename), bufsize); + fl_filename_setext(buf, bufsize, code_file_name_); } else { - return name; + strlcpy(buf, name, bufsize); } } /** Get the absolute path of the generated C++ header file, for example `/Users/matt/dev/src/`. - \return the path ending in '/' + \param[out] buf buffer to store result (ends with '/') + \param[in] bufsize size of buffer */ -std::string Project::headerfile_path() const { - std::string path = fl_filename_path_str(header_file_name); - if (Fluid.batch_mode) - return end_with_slash(fl_filename_absolute_str(path, Fluid.launch_path())); - else - return end_with_slash(fl_filename_absolute_str(path, projectfile_path())); +void fld::Project::headerfile_path(char *buf, int bufsize) const { + buf[0] = '\0'; + + char path[FL_PATH_MAX]; + fl_filename_path(path, FL_PATH_MAX, header_file_name_); + + char abs_path[FL_PATH_MAX]; + if (Fluid.batch_mode) { + fl_filename_absolute(abs_path, FL_PATH_MAX, path, Fluid.launch_path()); + } else { + char proj_path[FL_PATH_MAX]; + projectfile_path(proj_path, FL_PATH_MAX); + fl_filename_absolute(abs_path, FL_PATH_MAX, path, proj_path); + } + + fld_end_with_slash(buf, bufsize, abs_path); } /** - Get the generated C++ header file name including extension, for example `test.cxx`. - \return the file name without path + Get the generated C++ header file name including extension, for example `test.h`. + \param[out] buf buffer to store result + \param[in] bufsize size of buffer */ -std::string Project::headerfile_name() const { - std::string name = fl_filename_name_str(header_file_name); - if (name.empty()) { - if (!proj_filename) return std::string{}; - return fl_filename_setext_str(fl_filename_name_str(proj_filename), ".h"); +void fld::Project::headerfile_name(char *buf, int bufsize) const { + buf[0] = '\0'; + + const char *name = fl_filename_name(header_file_name_); + if (!name || !*name) { + // No name specified, use project filename with .h extension + if (!proj_filename) return; + strlcpy(buf, fl_filename_name(proj_filename), bufsize); + fl_filename_setext(buf, bufsize, ".h"); } else if (name[0] == '.') { - if (!proj_filename) return std::string{}; - return fl_filename_setext_str(fl_filename_name_str(proj_filename), header_file_name); + // Only extension specified, use project filename with this extension + if (!proj_filename) return; + strlcpy(buf, fl_filename_name(proj_filename), bufsize); + fl_filename_setext(buf, bufsize, header_file_name_); } else { - return name; + strlcpy(buf, name, bufsize); } } /** Get the absolute path of the generated i18n strings file, for example `/Users/matt/dev/`. - Although it may be more useful to put the text file into the same directory - with the source and header file, historically, the text is always saved with - the project file in interactive mode, and in the FLUID launch directory in - batch mode. - \return the path ending in '/' + \param[out] buf buffer to store result (ends with '/') + \param[in] bufsize size of buffer */ -std::string Project::stringsfile_path() const { - if (Fluid.batch_mode) - return Fluid.launch_path(); - else - return projectfile_path(); +void fld::Project::stringsfile_path(char *buf, int bufsize) const { + if (Fluid.batch_mode) { + strlcpy(buf, Fluid.launch_path(), bufsize); + } else { + projectfile_path(buf, bufsize); + } } /** Get the generated i18n text file name including extension, for example `test.po`. - \return the file name without path + \param[out] buf buffer to store result + \param[in] bufsize size of buffer */ -std::string Project::stringsfile_name() const { - if (!proj_filename) return std::string{}; +void fld::Project::stringsfile_name(char *buf, int bufsize) const { + buf[0] = '\0'; + if (!proj_filename) return; + + strlcpy(buf, fl_filename_name(proj_filename), bufsize); switch (i18n.type) { - default: return fl_filename_setext_str(fl_filename_name(proj_filename), ".txt"); - case FLD_I18N_TYPE_GNU: return fl_filename_setext_str(fl_filename_name(proj_filename), ".po"); - case FLD_I18N_TYPE_POSIX: return fl_filename_setext_str(fl_filename_name(proj_filename), ".msg"); + default: + fl_filename_setext(buf, bufsize, ".txt"); + break; + case FLD_I18N_TYPE_GNU: + fl_filename_setext(buf, bufsize, ".po"); + break; + case FLD_I18N_TYPE_POSIX: + fl_filename_setext(buf, bufsize, ".msg"); + break; } } /** Get the name of the project file without the filename extension. - \return the file name without path or extension + \param[out] buf buffer to store result + \param[in] bufsize size of buffer */ -std::string Project::basename() const { - if (!proj_filename) return std::string{}; - return fl_filename_setext_str(fl_filename_name(proj_filename), ""); +void fld::Project::basename(char *buf, int bufsize) const { + buf[0] = '\0'; + if (!proj_filename) return; + + strlcpy(buf, fl_filename_name(proj_filename), bufsize); + fl_filename_setext(buf, bufsize, ""); } @@ -198,36 +304,41 @@ std::string Project::basename() const { \see leave_project_dir(), pwd, in_project_dir */ -void Project::enter_project_dir() { - if (in_project_dir<0) { +void fld::Project::enter_project_dir() { + if (in_project_dir < 0) { fprintf(stderr, "** Fluid internal error: enter_project_dir() calls unmatched\n"); return; } in_project_dir++; // check if we are already in the project dir and do nothing if so - if (in_project_dir>1) return; + if (in_project_dir > 1) return; // check if there is an active project, and do nothing if there is none if (!proj_filename || !*proj_filename) { fprintf(stderr, "** Fluid internal error: enter_project_dir() no filename set\n"); return; } // store the current working directory for later - app_work_dir = fl_getcwd_str(); + fl_getcwd(app_work_dir_, FL_PATH_MAX); + // set the current directory to the path of our .fl file - std::string project_path = fl_filename_path_str(fl_filename_absolute_str(proj_filename)); - if (fl_chdir(project_path.c_str()) == -1) { + char abs_filename[FL_PATH_MAX]; + fl_filename_absolute(abs_filename, FL_PATH_MAX, proj_filename); + + char project_path[FL_PATH_MAX]; + fl_filename_path(project_path, FL_PATH_MAX, abs_filename); + + if (fl_chdir(project_path) == -1) { fprintf(stderr, "** Fluid internal error: enter_project_dir() can't chdir to %s: %s\n", - project_path.c_str(), strerror(errno)); + project_path, strerror(errno)); return; } - //fprintf(stderr, "chdir from %s to %s\n", app_work_dir.c_str(), fl_getcwd().c_str()); } /** Change the current working directory to the previous directory. \see enter_project_dir(), pwd, in_project_dir */ -void Project::leave_project_dir() { +void fld::Project::leave_project_dir() { if (in_project_dir == 0) { fprintf(stderr, "** Fluid internal error: leave_project_dir() calls unmatched\n"); return; @@ -236,27 +347,26 @@ void Project::leave_project_dir() { // still nested, stay in the project directory if (in_project_dir > 0) return; // no longer nested, return to the original, usually the application working directory - if (fl_chdir(app_work_dir.c_str()) < 0) { + if (fl_chdir(app_work_dir_) < 0) { fprintf(stderr, "** Fluid internal error: leave_project_dir() can't chdir back to %s : %s\n", - app_work_dir.c_str(), strerror(errno)); + app_work_dir_, strerror(errno)); } } /** - Alias for set_filename(""). - Instead, change proj_filename into a std::string and add clear_filename(). + Clear the project filename. */ -void Project::set_filename(std::nullptr_t) { - set_filename(std::string()); +void fld::Project::clear_filename() { + set_filename(0); } /** Set the filename of the current .fl design. - \param[in] c the new absolute filename and path + \param[in] c the new absolute filename and path (may be NULL to clear) */ -void Project::set_filename(const std::string &c) { +void fld::Project::set_filename(const char *c) { if (proj_filename) free((void *)proj_filename); - proj_filename = c.empty() ? nullptr : fl_strdup(c.c_str()); + proj_filename = (c && *c) ? strdup(c) : 0; if (proj_filename && !Fluid.batch_mode) Fluid.history.update(proj_filename); @@ -267,24 +377,32 @@ void Project::set_filename(const std::string &c) { /** Write the strings that are used in i18n. */ -void Project::write_strings() { +void fld::Project::write_strings() { Fluid.flush_text_widgets(); if (!proj_filename) { - Fluid.save_project_file(nullptr); + Fluid.save_project_file(0); if (!proj_filename) return; } - std::string filename = stringsfile_path() + stringsfile_name(); + + char path[FL_PATH_MAX]; + char name[FL_PATH_MAX]; + stringsfile_path(path, FL_PATH_MAX); + stringsfile_name(name, FL_PATH_MAX); + + char filename[FL_PATH_MAX]; + snprintf(filename, FL_PATH_MAX, "%s%s", path, name); + int x = fld::io::write_strings(*this, filename); if (Fluid.batch_mode) { if (x) { - fprintf(stderr, "%s : %s\n", filename.c_str(), strerror(errno)); + fprintf(stderr, "%s : %s\n", filename, strerror(errno)); exit(1); } } else { if (x) { - fl_message("Can't write %s: %s", filename.c_str(), strerror(errno)); + fl_message("Can't write %s: %s", filename, strerror(errno)); } else if (completion_button->value()) { - fl_message("Wrote %s", stringsfile_name().c_str()); + fl_message("Wrote %s", name); } } } @@ -307,31 +425,34 @@ void Project::write_strings() { \param[in] mfc default -1 to let \c mf control \c modflag_c, 0 to mark the code files current, 1 to mark it out of date. -2 to ignore changes to mf. */ -void Project::set_modflag(int mf, int mfc) { - const char *code_ext = nullptr; +void fld::Project::set_modflag(int mf, int mfc) { + const char *code_ext = 0; char new_title[FL_PATH_MAX]; // Update the modflag_c to the worst possible condition. We could be a bit // more graceful and compare modification times of the files, but C++ has // no API for that until C++17. - if (mf!=-1) { + if (mf != -1) { modflag = mf; - if (mfc==-1 && mf==1) + if (mfc == -1 && mf == 1) mfc = mf; } - if (mfc>=0) { + if (mfc >= 0) { modflag_c = mfc; } if (Fluid.main_window) { - std::string basename; - if (!proj_filename) basename = "Untitled.fl"; - else basename = fl_filename_name_str(std::string(proj_filename)); - code_ext = fl_filename_ext(code_file_name.c_str()); + const char *base; + if (!proj_filename) { + base = "Untitled.fl"; + } else { + base = fl_filename_name(proj_filename); + } + code_ext = fl_filename_ext(code_file_name_); char mod_star = modflag ? '*' : ' '; char mod_c_star = modflag_c ? '*' : ' '; snprintf(new_title, sizeof(new_title), "%s%c %s%c", - basename.c_str(), mod_star, code_ext, mod_c_star); + base, mod_star, code_ext, mod_c_star); const char *old_title = Fluid.main_window->label(); // only update the title if it actually changed if (!old_title || strcmp(old_title, new_title)) |
