summaryrefslogtreecommitdiff
path: root/fluid/Project.cxx
diff options
context:
space:
mode:
authormaxim nikonov <maxim.nikonov@hqo.co>2026-02-06 02:33:41 +0500
committermaxim nikonov <maxim.nikonov@hqo.co>2026-02-06 02:33:41 +0500
commit43e0a37906afabb0b3b091b8d3eac9a910cae50c (patch)
treed2a037c2bf0dc395fddb08e32ebfcf2795503b7c /fluid/Project.cxx
parent4ce4967c33d56e4b56d85d11fe0e0be91e159f5d (diff)
wip
Diffstat (limited to 'fluid/Project.cxx')
-rw-r--r--fluid/Project.cxx325
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))