From 43e0a37906afabb0b3b091b8d3eac9a910cae50c Mon Sep 17 00:00:00 2001 From: maxim nikonov Date: Fri, 6 Feb 2026 02:33:41 +0500 Subject: wip --- fluid/app/Image_Asset.cxx | 22 +- fluid/app/Image_Asset.h | 2 +- fluid/app/Menu.cxx | 79 ++++--- fluid/app/Snap_Action.cxx | 44 ++-- fluid/app/args.cxx | 56 +++-- fluid/app/args.h | 19 +- fluid/app/history.cxx | 62 ++--- fluid/app/history.h | 11 +- fluid/app/shell_command.cxx | 537 +++++++++++++++++++++++--------------------- fluid/app/shell_command.h | 64 +++--- fluid/app/templates.cxx | 4 +- 11 files changed, 467 insertions(+), 433 deletions(-) (limited to 'fluid/app') diff --git a/fluid/app/Image_Asset.cxx b/fluid/app/Image_Asset.cxx index 09550fac0..cea3cc058 100644 --- a/fluid/app/Image_Asset.cxx +++ b/fluid/app/Image_Asset.cxx @@ -209,8 +209,8 @@ void Image_Asset::write_static_rgb(fld::io::Code_Writer& f, const char* idata_na */ void Image_Asset::write_static(fld::io::Code_Writer& f, int compressed) { if (!image_) return; - const char *idata_name = f.unique_id(this, "idata", fl_filename_name(filename()), nullptr); - initializer_function_ = f.unique_id(this, "image", fl_filename_name(filename()), nullptr); + const char *idata_name = f.unique_id(this, "idata", fl_filename_name(filename()), 0); + initializer_function_ = f.unique_id(this, "image", fl_filename_name(filename()), 0); if (is_animated_gif_) { // Write animated gif image data... @@ -309,8 +309,8 @@ void Image_Asset::write_static(fld::io::Code_Writer& f, int compressed) { } else { // if FLUID runs from the command line, make sure that the image is not // only loaded but also rasterized, so we can write the RGB image data - Fl_RGB_Image* rgb_image = nullptr; - Fl_SVG_Image* svg_image = nullptr; + Fl_RGB_Image* rgb_image = 0; + Fl_SVG_Image* svg_image = 0; if (image_->d()>0) rgb_image = (Fl_RGB_Image*)image_->image(); if (rgb_image) @@ -343,7 +343,7 @@ void Image_Asset::write_static(fld::io::Code_Writer& f, int compressed) { void Image_Asset::write_file_error(fld::io::Code_Writer& f, const char *fmt) { f.write_c("#warning Cannot read %s file \"%s\": %s\n", fmt, filename(), strerror(errno)); Fluid.proj.enter_project_dir(); - f.write_c("// Searching in path \"%s\"\n", fl_getcwd(nullptr, FL_PATH_MAX)); + f.write_c("// Searching in path \"%s\"\n", fl_getcwd(0, FL_PATH_MAX)); Fluid.proj.leave_project_dir(); } @@ -434,10 +434,10 @@ void Image_Asset::write_inline(fld::io::Code_Writer& f, int inactive) { If the image asset has already been loaded, it is returned from the cache. If the image asset has not been loaded, it is loaded from the file system. - If the image asset cannot be loaded, nullptr is returned. + If the image asset cannot be loaded, 0 is returned. \param iname The filename of the image asset to find. - \returns The image asset, or nullptr if it cannot be loaded. + \returns The image asset, or 0 if it cannot be loaded. */ Image_Asset* Image_Asset::find(const char *iname) { if (!iname || !*iname) return 0; @@ -553,12 +553,12 @@ Image_Asset::~Image_Asset() { .pgm, .png, .ppm, .xbm, .xpm, and .svg (and .svgz if zlib support is enabled). The function returns a pointer to an Image_Asset object that references the selected image. If the user cancels the file chooser or - selects a file that does not exist, the function returns nullptr. + selects a file that does not exist, the function returns 0. \param oldname The default filename to display in the file chooser. \return A pointer to an Image_Asset object that references the selected - image, or nullptr if the user cancels the file chooser or selects a file + image, or 0 if the user cancels the file chooser or selects a file that does not exist. The asset is automaticly added to the global image asset map. */ @@ -572,8 +572,8 @@ Image_Asset *ui_find_image(const char *oldname) { #endif "})", oldname,1); - fl_file_chooser_ok_label(nullptr); - Image_Asset *ret = (name && *name) ? Image_Asset::find(name) : nullptr; + fl_file_chooser_ok_label(0); + Image_Asset *ret = (name && *name) ? Image_Asset::find(name) : 0; Fluid.proj.leave_project_dir(); return ret; } diff --git a/fluid/app/Image_Asset.h b/fluid/app/Image_Asset.h index f5376beaa..fcc8fb31c 100644 --- a/fluid/app/Image_Asset.h +++ b/fluid/app/Image_Asset.h @@ -32,7 +32,7 @@ private: // member variables bool is_animated_gif_ = false; ///< It's an animated gif. std::string filename_ { }; ///< Relative path to the image file int refcount_ = 0; ///< Reference count - Fl_Shared_Image *image_ = nullptr; ///< The actual image as managed by FLTK + Fl_Shared_Image *image_ = 0; ///< The actual image as managed by FLTK std::string initializer_function_ { }; ///< The name of the initializer function private: // methods diff --git a/fluid/app/Menu.cxx b/fluid/app/Menu.cxx index ab03a822d..54db5801f 100644 --- a/fluid/app/Menu.cxx +++ b/fluid/app/Menu.cxx @@ -35,11 +35,8 @@ extern void layout_suite_marker(Fl_Widget *, void *user_data); extern void select_layout_preset_cb(Fl_Widget *, void *user_data); extern Fl_Menu_Item main_layout_submenu_[]; -using namespace fld; - - void write_cb(Fl_Widget *, void *) { - Fluid.write_code_files(); + Fluid.write_code_files(0); } void openwidget_cb(Fl_Widget *, void *) { Fluid.edit_selected(); } void copy_cb(Fl_Widget*, void*) { Fluid.copy_selected(); } @@ -59,13 +56,13 @@ void manual_cb(Fl_Widget *, void *) { Fluid.show_help("index.html"); } -static void menu_file_new_cb(Fl_Widget *, void *) { Fluid.new_project(); } +static void menu_file_new_cb(Fl_Widget *, void *) { Fluid.new_project(1); } static void menu_file_new_from_template_cb(Fl_Widget *, void *) { Fluid.new_project_from_template(); } static void menu_file_open_cb(Fl_Widget *, void *) { Fluid.open_project_file(""); } static void menu_file_insert_cb(Fl_Widget *, void *) { Fluid.merge_project_file(""); } void menu_file_save_cb(Fl_Widget *, void *arg) { Fluid.save_project_file(arg); } static void menu_file_print_cb(Fl_Widget *, void *arg) { Fluid.print_snapshots(); } -void menu_file_open_history_cb(Fl_Widget *, void *v) { Fluid.open_project_file(std::string((const char*)v)); } +void menu_file_open_history_cb(Fl_Widget *, void *v) { Fluid.open_project_file((const char*)v); } static void menu_layout_sync_resize_cb(Fl_Menu_ *m, void*) { if (m->mvalue()->value()) Fluid.proj.tree.allow_layout = 1; else Fluid.proj.tree.allow_layout = 0; } @@ -88,21 +85,21 @@ void toggle_widgetbin_cb(Fl_Widget *, void *) { Fluid.toggle_widget_bin(); } \todo Shortcuts are all over the place (Alt, Ctrl, Command, Shift-Ctrl, function keys), and there should be a help page listing all shortcuts. */ -Fl_Menu_Item Application::main_menu[] = { - {"&File",0,nullptr,nullptr,FL_SUBMENU}, +Fl_Menu_Item fld::Application::main_menu[] = { + {"&File",0,0,0,FL_SUBMENU}, {"&New", FL_COMMAND+'n', menu_file_new_cb}, {"&Open...", FL_COMMAND+'o', menu_file_open_cb}, - {"&Insert...", FL_COMMAND+'i', menu_file_insert_cb, nullptr, FL_MENU_DIVIDER}, - {"&Save", FL_COMMAND+'s', menu_file_save_cb, nullptr}, + {"&Insert...", FL_COMMAND+'i', menu_file_insert_cb, 0, FL_MENU_DIVIDER}, + {"&Save", FL_COMMAND+'s', menu_file_save_cb, 0}, {"Save &As...", FL_COMMAND+FL_SHIFT+'s', menu_file_save_cb, (void*)1}, {"Sa&ve A Copy...", 0, menu_file_save_cb, (void*)2}, - {"&Revert...", 0, menu_file_revert_cb, nullptr, FL_MENU_DIVIDER}, - {"New &From Template...", FL_COMMAND+'N', menu_file_new_from_template_cb, nullptr}, - {"Save As &Template...", 0, save_template_cb, nullptr, FL_MENU_DIVIDER}, + {"&Revert...", 0, menu_file_revert_cb, 0, FL_MENU_DIVIDER}, + {"New &From Template...", FL_COMMAND+'N', menu_file_new_from_template_cb, 0}, + {"Save As &Template...", 0, save_template_cb, 0, FL_MENU_DIVIDER}, {"&Print...", FL_COMMAND+'p', menu_file_print_cb}, - {"Write &Code", FL_COMMAND+FL_SHIFT+'c', write_cb, nullptr}, + {"Write &Code", FL_COMMAND+FL_SHIFT+'c', write_cb, 0}, {"MergeBack Code", FL_COMMAND+FL_SHIFT+'m', mergeback_cb, 0}, - {"&Write Strings", FL_COMMAND+FL_SHIFT+'w', write_strings_cb, nullptr, FL_MENU_DIVIDER}, + {"&Write Strings", FL_COMMAND+FL_SHIFT+'w', write_strings_cb, 0, FL_MENU_DIVIDER}, {Fluid.history.relpath[0], FL_COMMAND+'1', menu_file_open_history_cb, Fluid.history.abspath[0]}, {Fluid.history.relpath[1], FL_COMMAND+'2', menu_file_open_history_cb, Fluid.history.abspath[1]}, {Fluid.history.relpath[2], FL_COMMAND+'3', menu_file_open_history_cb, Fluid.history.abspath[2]}, @@ -114,67 +111,67 @@ Fl_Menu_Item Application::main_menu[] = { {Fluid.history.relpath[8], FL_COMMAND+'9', menu_file_open_history_cb, Fluid.history.abspath[8]}, {Fluid.history.relpath[9], 0, menu_file_open_history_cb, Fluid.history.abspath[9], FL_MENU_DIVIDER}, {"&Quit", FL_COMMAND+'q', exit_cb}, - {nullptr}, - {"&Edit",0,nullptr,nullptr,FL_SUBMENU}, + {0}, + {"&Edit",0,0,0,FL_SUBMENU}, {"&Undo", FL_COMMAND+'z', fld::proj::Undo::undo_cb}, - {"&Redo", FL_COMMAND+FL_SHIFT+'z', fld::proj::Undo::redo_cb, nullptr, FL_MENU_DIVIDER}, + {"&Redo", FL_COMMAND+FL_SHIFT+'z', fld::proj::Undo::redo_cb, 0, FL_MENU_DIVIDER}, {"C&ut", FL_COMMAND+'x', cut_cb}, {"&Copy", FL_COMMAND+'c', copy_cb}, {"&Paste", FL_COMMAND+'v', paste_cb}, {"Dup&licate", FL_COMMAND+'u', duplicate_cb}, - {"&Delete", FL_Delete, delete_cb, nullptr, FL_MENU_DIVIDER}, + {"&Delete", FL_Delete, delete_cb, 0, FL_MENU_DIVIDER}, {"Select &All", FL_COMMAND+'a', select_all_cb}, - {"Select &None", FL_COMMAND+FL_SHIFT+'a', select_none_cb, nullptr, FL_MENU_DIVIDER}, + {"Select &None", FL_COMMAND+FL_SHIFT+'a', select_none_cb, 0, FL_MENU_DIVIDER}, {"Pr&operties...", FL_F+1, openwidget_cb}, {"&Sort",0,sort_cb}, {"&Earlier", FL_F+2, earlier_cb}, {"&Later", FL_F+3, later_cb}, {"&Group", FL_F+7, group_cb}, - {"Ung&roup", FL_F+8, ungroup_cb,nullptr, FL_MENU_DIVIDER}, + {"Ung&roup", FL_F+8, ungroup_cb,0, FL_MENU_DIVIDER}, {"Hide O&verlays",FL_COMMAND+FL_SHIFT+'o',toggle_overlays}, {"Hide Guides",FL_COMMAND+FL_SHIFT+'g',toggle_guides}, {"Hide Restricted",FL_COMMAND+FL_SHIFT+'r',toggle_restricted}, {"Show Widget &Bin...",FL_ALT+'b',toggle_widgetbin_cb}, - {"Show Code View",FL_ALT+'c', (Fl_Callback*)toggle_codeview_cb, nullptr, FL_MENU_DIVIDER}, + {"Show Code View",FL_ALT+'c', (Fl_Callback*)toggle_codeview_cb, 0, FL_MENU_DIVIDER}, {"Settings...",FL_ALT+'p',show_settings_cb}, - {nullptr}, - {"&New", 0, nullptr, (void *)New_Menu, FL_SUBMENU_POINTER}, - {"&Layout",0,nullptr,nullptr,FL_SUBMENU}, - {"&Align",0,nullptr,nullptr,FL_SUBMENU}, + {0}, + {"&New", 0, 0, (void *)New_Menu, FL_SUBMENU_POINTER}, + {"&Layout",0,0,0,FL_SUBMENU}, + {"&Align",0,0,0,FL_SUBMENU}, {"&Left",0,(Fl_Callback *)align_widget_cb,(void*)10}, {"&Center",0,(Fl_Callback *)align_widget_cb,(void*)11}, {"&Right",0,(Fl_Callback *)align_widget_cb,(void*)12}, {"&Top",0,(Fl_Callback *)align_widget_cb,(void*)13}, {"&Middle",0,(Fl_Callback *)align_widget_cb,(void*)14}, {"&Bottom",0,(Fl_Callback *)align_widget_cb,(void*)15}, - {nullptr}, - {"&Space Evenly",0,nullptr,nullptr,FL_SUBMENU}, + {0}, + {"&Space Evenly",0,0,0,FL_SUBMENU}, {"&Across",0,(Fl_Callback *)align_widget_cb,(void*)20}, {"&Down",0,(Fl_Callback *)align_widget_cb,(void*)21}, - {nullptr}, - {"&Make Same Size",0,nullptr,nullptr,FL_SUBMENU}, + {0}, + {"&Make Same Size",0,0,0,FL_SUBMENU}, {"&Width",0,(Fl_Callback *)align_widget_cb,(void*)30}, {"&Height",0,(Fl_Callback *)align_widget_cb,(void*)31}, {"&Both",0,(Fl_Callback *)align_widget_cb,(void*)32}, - {nullptr}, - {"&Center In Group",0,nullptr,nullptr,FL_SUBMENU}, + {0}, + {"&Center In Group",0,0,0,FL_SUBMENU}, {"&Horizontal",0,(Fl_Callback *)align_widget_cb,(void*)40}, {"&Vertical",0,(Fl_Callback *)align_widget_cb,(void*)41}, - {nullptr}, - {"Synchronized Resize", 0, (Fl_Callback*)menu_layout_sync_resize_cb, nullptr, FL_MENU_TOGGLE|FL_MENU_DIVIDER }, - {"&Grid and Size Settings...",FL_COMMAND+'g',show_grid_cb, nullptr, FL_MENU_DIVIDER}, + {0}, + {"Synchronized Resize", 0, (Fl_Callback*)menu_layout_sync_resize_cb, 0, FL_MENU_TOGGLE|FL_MENU_DIVIDER }, + {"&Grid and Size Settings...",FL_COMMAND+'g',show_grid_cb, 0, FL_MENU_DIVIDER}, {"Presets", 0, layout_suite_marker, (void*)main_layout_submenu_, FL_SUBMENU_POINTER }, - {"Application", 0, select_layout_preset_cb, (void*)nullptr, FL_MENU_RADIO|FL_MENU_VALUE }, + {"Application", 0, select_layout_preset_cb, (void*)0, FL_MENU_RADIO|FL_MENU_VALUE }, {"Dialog", 0, select_layout_preset_cb, (void*)1, FL_MENU_RADIO }, {"Toolbox", 0, select_layout_preset_cb, (void*)2, FL_MENU_RADIO }, - {nullptr}, + {0}, {"&Shell", 0, Fd_Shell_Command_List::menu_marker, (void*)Fd_Shell_Command_List::default_menu, FL_SUBMENU_POINTER}, - {"&Help",0,nullptr,nullptr,FL_SUBMENU}, + {"&Help",0,0,0,FL_SUBMENU}, {"&Rapid development with FLUID...",0,help_cb}, - {"&FLTK Programmers Manual...",0,manual_cb, nullptr, FL_MENU_DIVIDER}, + {"&FLTK Programmers Manual...",0,manual_cb, 0, FL_MENU_DIVIDER}, {"&About FLUID...",0,about_cb}, - {nullptr}, -{nullptr}}; + {0}, +{0}}; /** Show or hide the code preview window. diff --git a/fluid/app/Snap_Action.cxx b/fluid/app/Snap_Action.cxx index 2ec7affad..51cdb9817 100644 --- a/fluid/app/Snap_Action.cxx +++ b/fluid/app/Snap_Action.cxx @@ -112,13 +112,13 @@ static Layout_Suite static_suite_list[] = { Fl_Menu_Item main_layout_submenu_[] = { { static_suite_list[0].menu_label, 0, select_layout_suite_cb, (void*)0, FL_MENU_RADIO|FL_MENU_VALUE }, { static_suite_list[1].menu_label, 0, select_layout_suite_cb, (void*)1, FL_MENU_RADIO }, - { nullptr } + { 0 } }; static Fl_Menu_Item static_choice_menu[] = { { static_suite_list[0].menu_label }, { static_suite_list[1].menu_label }, - { nullptr } + { 0 } }; @@ -131,17 +131,17 @@ void layout_suite_marker(Fl_Widget *, void *) { void select_layout_suite_cb(Fl_Widget *, void *user_data) { int index = (int)(fl_intptr_t)user_data; assert(index >= 0); - assert(index < Fluid.layout_list.list_size_); - Fluid.layout_list.current_suite(index); - Fluid.layout_list.update_dialogs(); + assert(index < Fluid.layout_list->list_size_); + Fluid.layout_list->current_suite(index); + Fluid.layout_list->update_dialogs(); } void select_layout_preset_cb(Fl_Widget *, void *user_data) { int index = (int)(fl_intptr_t)user_data; assert(index >= 0); assert(index < 3); - Fluid.layout_list.current_preset(index); - Fluid.layout_list.update_dialogs(); + Fluid.layout_list->current_preset(index); + Fluid.layout_list->update_dialogs(); } void edit_layout_preset_cb(Fl_Button *w, void *user_data) { @@ -149,10 +149,10 @@ void edit_layout_preset_cb(Fl_Button *w, void *user_data) { assert(index >= 0); assert(index < 3); if (user_data == LOAD) { - w->value(Fluid.layout_list.current_preset() == index); + w->value(Fluid.layout_list->current_preset() == index); } else { - Fluid.layout_list.current_preset(index); - Fluid.layout_list.update_dialogs(); + Fluid.layout_list->current_preset(index); + Fluid.layout_list->update_dialogs(); } } @@ -412,7 +412,7 @@ void Layout_Suite::update_label() { if (menu_label) ::free(menu_label); menu_label = fl_strdup(sym.c_str()); - Fluid.layout_list.update_menu_labels(); + Fluid.layout_list->update_menu_labels(); } /** @@ -425,7 +425,7 @@ void Layout_Suite::name(const char *n) { if (n) name_ = fl_strdup(n); else - name_ = nullptr; + name_ = 0; update_label(); } @@ -433,9 +433,9 @@ void Layout_Suite::name(const char *n) { Initialize the class for first use. */ void Layout_Suite::init() { - name_ = nullptr; - menu_label = nullptr; - layout[0] = layout[1] = layout[2] = nullptr; + name_ = 0; + menu_label = 0; + layout[0] = layout[1] = layout[2] = 0; storage_ = FLD_TOOL_STORE_INTERNAL; } @@ -630,7 +630,7 @@ Layout_List::~Layout_List() { Update the Setting dialog and menus to reflect the current Layout selection state. */ void Layout_List::update_dialogs() { - static Fl_Menu_Item *preset_menu = nullptr; + static Fl_Menu_Item *preset_menu = 0; if (!preset_menu) { preset_menu = (Fl_Menu_Item*)Fluid.main_menubar->find_item(select_layout_preset_cb); assert(preset_menu); @@ -665,7 +665,7 @@ void Layout_List::update_menu_labels() { */ int Layout_List::load(const std::string &filename) { remove_all(FLD_TOOL_STORE_FILE); - Fl_Preferences prefs(filename.c_str(), "layout.fluid.fltk.org", nullptr, Fl_Preferences::C_LOCALE); + Fl_Preferences prefs(filename.c_str(), "layout.fluid.fltk.org", 0, Fl_Preferences::C_LOCALE); read(prefs, FLD_TOOL_STORE_FILE); return 0; } @@ -675,7 +675,7 @@ int Layout_List::load(const std::string &filename) { */ int Layout_List::save(const std::string &filename) { assert(this); - Fl_Preferences prefs(filename.c_str(), "layout.fluid.fltk.org", nullptr, (Fl_Preferences::Root)(Fl_Preferences::C_LOCALE|Fl_Preferences::CLEAR)); + Fl_Preferences prefs(filename.c_str(), "layout.fluid.fltk.org", 0, (Fl_Preferences::Root)(Fl_Preferences::C_LOCALE|Fl_Preferences::CLEAR)); prefs.clear(); write(prefs, FLD_TOOL_STORE_FILE); return 0; @@ -829,7 +829,7 @@ void Layout_List::current_preset(int ix) { Allocate enough space for n entries in the list. */ void Layout_List::capacity(int n) { - static Fl_Menu_Item *suite_menu = nullptr; + static Fl_Menu_Item *suite_menu = 0; if (!suite_menu) suite_menu = (Fl_Menu_Item*)Fluid.main_menubar->find_item(layout_suite_marker); @@ -1467,11 +1467,11 @@ class Fd_Snap_Sibling : public Snap_Action { protected: Fl_Widget *best_match; public: - Fd_Snap_Sibling() : best_match(nullptr) { } + Fd_Snap_Sibling() : best_match(0) { } virtual int sibling_check(Snap_Data &d, Fl_Widget *s) = 0; void check(Snap_Data &d) override { clr(); - best_match = nullptr; + best_match = 0; if (!d.wgt) return; if (!d.wgt->parent->is_a(FLD_NODE_TYPE_Group)) return; int dsib_min = 1024; @@ -1707,7 +1707,7 @@ Snap_Action *Snap_Action::list[] = { &snap_widget_ideal_width, &snap_widget_ideal_height, - nullptr + 0 }; // ---- draw alignment marks ------------------------------------------- MARK: - diff --git a/fluid/app/args.cxx b/fluid/app/args.cxx index b9d958e8c..70faebafc 100644 --- a/fluid/app/args.cxx +++ b/fluid/app/args.cxx @@ -22,8 +22,21 @@ #include #include -using namespace fld; -using namespace fld::app; +#include +#include "../src/flstring.h" + + +fld::app::Args::Args() +: update_file(0), + compile_file(0), + compile_strings(0), + show_version(0) +{ + code_filename[0] = '\0'; + header_filename[0] = '\0'; + autodoc_path[0] = '\0'; +} + /** Load args from command line into variables. @@ -33,12 +46,12 @@ using namespace fld::app; \return 0 if the args were handled successfully, -1 if there was an error and the usage message was shown. */ -int Args::load(int argc,char **argv) { +int fld::app::Args::load(int argc, char **argv) { int i = 1; Fl::args_to_utf8(argc, argv); // for MSYS2/MinGW - if ( (Fl::args(argc,argv,i,arg_cb) == 0) // unsupported argument found - || (Fluid.batch_mode && (i != argc-1)) // .fl filename missing - || (!Fluid.batch_mode && (i < argc-1)) // more than one filename found + if ( (Fl::args(argc, argv, i, arg_cb) == 0) // unsupported argument found + || (Fluid.batch_mode && (i != argc - 1)) // .fl filename missing + || (!Fluid.batch_mode && (i < argc - 1)) // more than one filename found || (argv[i] && (argv[i][0] == '-'))) { // unknown option static const char *msg = "usage: %s name.fl\n" @@ -50,13 +63,12 @@ int Args::load(int argc,char **argv) { " --help : brief usage information\n" " --version, -v : print fluid version number\n" " -d : enable internal debugging\n"; - const char *app_name = nullptr; - if ( (argc > 0) && argv[0] && argv[0][0] ) + const char *app_name = 0; + if ((argc > 0) && argv[0] && argv[0][0]) app_name = fl_filename_name(argv[0]); - if ( !app_name || !app_name[0]) + if (!app_name || !app_name[0]) app_name = "fluid"; #ifdef _MSC_VER - // TODO: if this is fluid-cmd, use stderr and not fl_message fl_message(msg, app_name); #else fprintf(stderr, msg, app_name); @@ -67,7 +79,7 @@ int Args::load(int argc,char **argv) { } -int Args::arg_cb(int argc, char** argv, int& i) { +int fld::app::Args::arg_cb(int argc, char** argv, int& i) { return Fluid.args.arg(argc, argv, i); } @@ -79,11 +91,11 @@ int Args::arg_cb(int argc, char** argv, int& i) { \param[inout] i current argument index \return number of arguments used; if 0, the argument is not supported */ -int Args::arg(int argc, char** argv, int& i) { +int fld::app::Args::arg(int argc, char** argv, int& i) { if (argv[i][0] != '-') return 0; if (argv[i][1] == 'd' && !argv[i][2]) { - Fluid.debug_external_editor=1; + Fluid.debug_external_editor = 1; i++; return 1; } if (argv[i][1] == 'u' && !argv[i][2]) { @@ -96,7 +108,7 @@ int Args::arg(int argc, char** argv, int& i) { Fluid.batch_mode++; i++; return 1; } - if ((strcmp(argv[i], "-v")==0) || (strcmp(argv[i], "--version")==0)) { + if ((strcmp(argv[i], "-v") == 0) || (strcmp(argv[i], "--version") == 0)) { show_version = 1; i++; return 1; } @@ -106,31 +118,29 @@ int Args::arg(int argc, char** argv, int& i) { Fluid.batch_mode++; i++; return 1; } - if (argv[i][1] == 'o' && !argv[i][2] && i+1 < argc) { - code_filename = argv[i+1]; + if (argv[i][1] == 'o' && !argv[i][2] && i + 1 < argc) { + strlcpy(code_filename, argv[i + 1], FL_PATH_MAX); Fluid.batch_mode++; i += 2; return 2; } #ifndef NDEBUG - if ((i+1 < argc) && (strcmp(argv[i], "--autodoc") == 0)) { - autodoc_path = argv[i+1]; + if ((i + 1 < argc) && (strcmp(argv[i], "--autodoc") == 0)) { + strlcpy(autodoc_path, argv[i + 1], FL_PATH_MAX); i += 2; return 2; } #endif - if (strcmp(argv[i], "--help")==0) { + if (strcmp(argv[i], "--help") == 0) { return 0; } if (argv[i][1] == 'h' && !argv[i][2]) { - if ( (i+1 < argc) && (argv[i+1][0] != '-') ) { - header_filename = argv[i+1]; + if ((i + 1 < argc) && (argv[i + 1][0] != '-')) { + strlcpy(header_filename, argv[i + 1], FL_PATH_MAX); Fluid.batch_mode++; i += 2; return 2; } else { - // a lone "-h" without a filename will output the help string return 0; } } return 0; } - diff --git a/fluid/app/args.h b/fluid/app/args.h index 80dfa2290..1165c4f58 100644 --- a/fluid/app/args.h +++ b/fluid/app/args.h @@ -17,7 +17,7 @@ #ifndef FLUID_APP_ARGS_H #define FLUID_APP_ARGS_H -#include +#include namespace fld { namespace app { @@ -29,21 +29,21 @@ class Args { int arg(int argc, char** argv, int& i); public: /// Set, if Fluid was started with the command line argument -u - int update_file { 0 }; // fluid -u + int update_file; /// Set, if Fluid was started with the command line argument -c - int compile_file { 0 }; // fluid -c + int compile_file; /// Set, if Fluid was started with the command line argument -cs - int compile_strings { 0 }; // fluid -cs + int compile_strings; /// command line arguments that overrides the generate code file extension or name - std::string code_filename { }; // fluid -o filename + char code_filename[FL_PATH_MAX]; /// command line arguments that overrides the generate header file extension or name - std::string header_filename { }; // fluid -h filename + char header_filename[FL_PATH_MAX]; /// if set, generate images for automatic documentation in this directory - std::string autodoc_path { }; // fluid --autodoc path + char autodoc_path[FL_PATH_MAX]; /// Set, if Fluid was started with the command line argument -v - int show_version { 0 }; // fluid -v + int show_version; /// Constructor. - Args() = default; + Args(); // Load args from command line into variables. int load(int argc, char **argv); }; @@ -52,4 +52,3 @@ public: } // namespace fld #endif // FLUID_APP_ARGS_H - diff --git a/fluid/app/history.cxx b/fluid/app/history.cxx index 7eadb5469..91b2f0b99 100644 --- a/fluid/app/history.cxx +++ b/fluid/app/history.cxx @@ -17,11 +17,20 @@ #include "app/history.h" #include "Fluid.h" +#include "tools/filename.h" #include "../src/flstring.h" -using namespace fld; -using namespace fld::app; + +fld::app::History::History() { + int i, j; + for (i = 0; i < 10; i++) { + for (j = 0; j < FL_PATH_MAX; j++) { + abspath[i][j] = '\0'; + relpath[i][j] = '\0'; + } + } +} /** @@ -31,25 +40,23 @@ using namespace fld::app; It also computes and stores the relative filepaths for display in the main menu. */ -void History::load() { - int i; // Looping var - int max_files; +void fld::app::History::load() { + int i; + int max_files; Fluid.preferences.get("recent_files", max_files, 5); if (max_files > 10) max_files = 10; - for (i = 0; i < max_files; i ++) { - Fluid.preferences.get( Fl_Preferences::Name("file%d", i), abspath[i], "", sizeof(abspath[i])); + for (i = 0; i < max_files; i++) { + Fluid.preferences.get(Fl_Preferences::Name("file%d", i), abspath[i], "", sizeof(abspath[i])); if (abspath[i][0]) { - // Make a shortened version of the filename for the menu... - std::string fn = fl_filename_shortened(abspath[i], 48); - strncpy(relpath[i], fn.c_str(), sizeof(relpath[i]) - 1); + fl_filename_shortened(relpath[i], sizeof(relpath[i]), abspath[i], 48); if (i == 9) Fluid.history_item[i].flags = FL_MENU_DIVIDER; else Fluid.history_item[i].flags = 0; } else break; } - for (; i < 10; i ++) { + for (; i < 10; i++) { if (i) Fluid.history_item[i-1].flags |= FL_MENU_DIVIDER; Fluid.history_item[i].hide(); } @@ -64,19 +71,24 @@ void History::load() { \param[in] project_file path and filename of .fl project file, will be converted into an absolute file path based on the current working directory. */ -void History::update(std::string project_file) { - int i; // Looping var - int max_files; +void fld::app::History::update(const char *project_file) { + int i; + int max_files; + + if (!project_file || !project_file[0]) return; Fluid.preferences.get("recent_files", max_files, 5); if (max_files > 10) max_files = 10; - std::string absolute = fld::fix_separators(fl_filename_absolute_str(project_file)); - for (i = 0; i < max_files; i ++) + char absolute[FL_PATH_MAX]; + fl_filename_absolute(absolute, FL_PATH_MAX, project_file); + fld_fix_separators(absolute); + + for (i = 0; i < max_files; i++) #if defined(_WIN32) || defined(__APPLE__) - if (!strcasecmp(absolute.c_str(), abspath[i])) break; + if (!strcasecmp(absolute, abspath[i])) break; #else - if (!strcmp(absolute.c_str(), abspath[i])) break; + if (!strcmp(absolute, abspath[i])) break; #endif // _WIN32 || __APPLE__ // Does the first entry match? @@ -92,24 +104,22 @@ void History::update(std::string project_file) { memmove(relpath + 1, relpath, i * sizeof(relpath[0])); // Put the new file at the top... - strlcpy(abspath[0], absolute.c_str(), sizeof(abspath[0])); - std::string fn = fl_filename_shortened(absolute, 48); - strncpy(relpath[0], fn.c_str(), sizeof(relpath[0]) - 1); + strlcpy(abspath[0], absolute, sizeof(abspath[0])); + fl_filename_shortened(relpath[0], sizeof(relpath[0]), absolute, 48); // Update the menu items as needed... - for (i = 0; i < max_files; i ++) { - Fluid.preferences.set( Fl_Preferences::Name("file%d", i), abspath[i]); + for (i = 0; i < max_files; i++) { + Fluid.preferences.set(Fl_Preferences::Name("file%d", i), abspath[i]); if (abspath[i][0]) { if (i == 9) Fluid.history_item[i].flags = FL_MENU_DIVIDER; else Fluid.history_item[i].flags = 0; } else break; } - for (; i < 10; i ++) { - Fluid.preferences.set( Fl_Preferences::Name("file%d", i), ""); + for (; i < 10; i++) { + Fluid.preferences.set(Fl_Preferences::Name("file%d", i), ""); if (i) Fluid.history_item[i-1].flags |= FL_MENU_DIVIDER; Fluid.history_item[i].hide(); } Fluid.preferences.flush(); } - diff --git a/fluid/app/history.h b/fluid/app/history.h index e32723b4b..99200757a 100644 --- a/fluid/app/history.h +++ b/fluid/app/history.h @@ -17,8 +17,6 @@ #ifndef FLUID_APP_HISTORY_H #define FLUID_APP_HISTORY_H -#include - #include namespace fld { @@ -27,19 +25,18 @@ namespace app { class History { public: /// Stores the absolute filename of the last 10 project files, saved in app preferences. - char abspath[10][FL_PATH_MAX] { }; + char abspath[10][FL_PATH_MAX]; /// The list of filenames as displayed in the main menu. - char relpath[10][FL_PATH_MAX] { }; + char relpath[10][FL_PATH_MAX]; // Create the project file history. - History() = default; + History(); // Load the project history from the preferences database. void load(); // Add a new file to the project history using absolute paths. - void update(std::string project_file); + void update(const char *project_file); }; } // namespace app } // namespace fld #endif // FLUID_APP_HISTORY_H - diff --git a/fluid/app/shell_command.cxx b/fluid/app/shell_command.cxx index 05bc28ec0..0a9a04121 100644 --- a/fluid/app/shell_command.cxx +++ b/fluid/app/shell_command.cxx @@ -1,5 +1,5 @@ // -// Shell Command database coe for the Fast Light Tool Kit (FLTK). +// Shell Command database code for the Fast Light Tool Kit (FLTK). // // Copyright 1998-2025 by Bill Spitzak and others. // @@ -14,87 +14,6 @@ // https://www.fltk.org/bugs.php // -// in progress: -// FLUID comes with example shell commands to build the current project file -// and run the project. This is accomplished by calling `fltk-config` on the -// files generated by FLUID, and by calling the executable directly. -// -// If the user wants more complex commands, he can add or modify them in the -// "Shell" settings panel. Modified shell commands are saved with the .fl -// file. - -// The Shell panel has a list of shell commands in the upper half. Under the -// list are buttons to add, duplicate, and delete shell commands. A popup -// menu offers import and export functionality and a list of sample scripts. -// We may want to add up and down buttons, so the user can change the -// order of commands. - -// Selecting any shell command in the list fills in and activates a list of -// options in the lower half of the panel. Those settings are: -// - Name: the name of the shell command in the list -// - Label: the label in the pulldown menu (could be the same as name?) -// - Shortcut: shortcut key to launch the command -// - Storage: where to store this shell command -// - Condition: pulldown menu to make the entry conditional for various -// target platforms, for example, a "Windows only" entry would only be added -// to the Shell menu on a Windows machine. Other options could be: -// - Linux only, macOS only, never (to make a list header!?), inactive? -// - Command: a multiline input for the actual shell command -// - Variables: a pulldown menu that insert variable names like $ -// - options to save project, code, and strings before running -// - test-run button - -// TODO: add @APPDIR@? -// TODO: get a macro to find `fltk-config` @FLTK_CONFIG@ -// TODO: add an input field so the user can insert their preferred file and path for fltk-config (user setting) -// `fltk-config` is actually tricky to find -// for live builds, we could check the program launch directory -// if we know where build/Xcode/bin/Debug/fluid is, we -// may or may not find ./build/Xcode/fltk-config -// on macOS with homebrew, we find /opt/homebrew/bin/fltk-config but the user -// can set their own install path. -// We can query the shell path, but that requires knowing the users shell (echo $SHELL). -// We can run the shell as a login shell with `-l`, so the user $PTH is set: /bin/bash -l -c 'fltk-config' -// The shell should output the path of the fltk-config that it found and why it is using that one. -// This can also output the fltk-config version. -// TODO: add a bunch of sensible sample shell commands -// TODO: when this new feature is used for the very first time, import two or three samples as initial user setting -// TODO: make the settings dialog resizable -// TODO: make g_shell_config static, not a pointer, but don't load anything in batch mode - -// FEATURE: fld::Tool_Store icons are currently redundant with @file and @save and could be improved -// FEATURE: hostname, username, getenv support? -// FEATURE: add the files ./fluid.prefs and ./fluid.user.prefs as tool locations -// FEATURE: interpret compiler output, for example: clang, and highlight errors and warnings -// `.../shell_command.cxx:71:2: error: test` -// `71 | #error test` -// `clang++: error: no such file or directory: '.../shell_command.o'` -// would make the error message clickable in the shell window and could select the widget, -// open the matching editor in the widget panel, and highlight the line in SourceView. - -/* - Some ideas: - - default shell is in $SHELL on linux and macOS - - On macOS, we can write Apple Scripts: - - #!/usr/bin/env osascript - say "@BASENAME@" - - osascript < #include +#include -using namespace fld; - -static std::string fltk_config_cmd; static Fl_Process s_proc; /** See if shell command is running (public) */ -bool shell_command_running() { - return s_proc.desc() ? true : false; +int shell_command_running() { + return s_proc.desc() ? 1 : 0; } /** \class Fl_Process @@ -130,13 +47,13 @@ bool shell_command_running() { Create a process manager */ Fl_Process::Fl_Process() { + _fpt = 0; } /** Destroy the project manager. */ Fl_Process::~Fl_Process() { - // TODO: check what we need to do if a task is still running if (_fpt) close(); } @@ -150,13 +67,13 @@ Fl_Process::~Fl_Process() { FILE * Fl_Process::popen(const char *cmd, const char *mode) { #if defined(_WIN32) && !defined(__CYGWIN__) // PRECONDITIONS - if (!mode || !*mode || (*mode!='r' && *mode!='w') ) return nullptr; + if (!mode || !*mode || (*mode!='r' && *mode!='w') ) return 0; if (_fpt) close(); // close first before reuse ptmode = *mode; pin[0] = pin[1] = pout[0] = pout[1] = perr[0] = perr[1] = INVALID_HANDLE_VALUE; // stderr to stdout wanted ? - int fusion = (strstr(cmd,"2>&1") !=nullptr); + int fusion = (strstr(cmd,"2>&1") != 0); // Create windows pipes if (!createPipe(pin) || !createPipe(pout) || (!fusion && !createPipe(perr) ) ) @@ -170,8 +87,8 @@ FILE * Fl_Process::popen(const char *cmd, const char *mode) { si.hStdOutput = pout[1]; si.hStdError = fusion ? pout[1] : perr [1]; - if ( CreateProcess(nullptr, (LPTSTR) cmd,nullptr,nullptr,TRUE, - DETACHED_PROCESS,nullptr,nullptr, &si, &pi)) { + if ( CreateProcess(0, (LPTSTR) cmd, 0, 0, TRUE, + DETACHED_PROCESS, 0, 0, &si, &pi)) { // don't need theses handles inherited by child process: clean_close(pin[0]); clean_close(pout[1]); clean_close(perr[1]); HANDLE & h = *mode == 'r' ? pout[0] : pin[1]; @@ -198,13 +115,13 @@ int Fl_Process::close() { clean_close(perr[0]); clean_close(pin[1]); clean_close(pout[0]); - _fpt = nullptr; + _fpt = 0; return 0; } return -1; #else int ret = ::pclose(_fpt); - _fpt=nullptr; + _fpt = 0; return ret; #endif } @@ -223,16 +140,14 @@ FILE *Fl_Process::desc() const { \param[out] line buffer to receive the line \param[in] s size of the provided buffer - \return nullptr if an error occurred, otherwise a pointer to the string + \return 0 if an error occurred, otherwise a pointer to the string */ char *Fl_Process::get_line(char * line, size_t s) const { - return _fpt ? fgets(line, (int)s, _fpt) : nullptr; + return _fpt ? fgets(line, (int)s, _fpt) : 0; } // returns fileno(FILE*): // (file must be open, i.e. _fpt must be non-null) -// *FIXME* we should find a better solution for the 'fileno' issue -// non null if file is open int Fl_Process::get_fileno() const { #ifdef _MSC_VER return _fileno(_fpt); // suppress MSVC warning @@ -243,19 +158,19 @@ int Fl_Process::get_fileno() const { #if defined(_WIN32) && !defined(__CYGWIN__) -bool Fl_Process::createPipe(HANDLE * h, BOOL bInheritHnd) { +int Fl_Process::createPipe(HANDLE * h, BOOL bInheritHnd) { SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = nullptr; + sa.lpSecurityDescriptor = 0; sa.bInheritHandle = bInheritHnd; - return CreatePipe (&h[0],&h[1],&sa,0) ? true : false; + return CreatePipe (&h[0],&h[1],&sa,0) ? 1 : 0; } FILE *Fl_Process::freeHandles() { clean_close(pin[0]); clean_close(pin[1]); clean_close(pout[0]); clean_close(pout[1]); clean_close(perr[0]); clean_close(perr[1]); - return nullptr; // convenient for error management + return 0; // convenient for error management } void Fl_Process::clean_close(HANDLE& h) { @@ -270,24 +185,23 @@ void Fl_Process::clean_close(HANDLE& h) { Prepare FLUID for running a shell command according to the command flags. \param[in] flags set various flags to save the project, code, and string before running the command - \return false if the previous command is still running + \return 0 if the previous command is still running */ -static bool prepare_shell_command(int flags) { -// settings_window->hide(); +static int prepare_shell_command(int flags) { if (s_proc.desc()) { fl_alert("Previous shell command still running!"); - return false; + return 0; } if (flags & Fd_Shell_Command::SAVE_PROJECT) { - Fluid.save_project_file(nullptr); + Fluid.save_project_file(0); } if (flags & Fd_Shell_Command::SAVE_SOURCECODE) { - Fluid.write_code_files(true); + Fluid.write_code_files(1); } if (flags & Fd_Shell_Command::SAVE_STRINGS) { Fluid.proj.write_strings(); } - return true; + return 1; } /** @@ -312,7 +226,7 @@ void shell_timer_cb(void*) { void shell_pipe_cb(FL_SOCKET, void*) { char line[1024]=""; // Line from command output... - if (s_proc.get_line(line, sizeof(line)) != nullptr) { + if (s_proc.get_line(line, sizeof(line)) != 0) { // Add the line to the output list... shell_run_terminal->append(line); } else { @@ -324,38 +238,77 @@ void shell_pipe_cb(FL_SOCKET, void*) { } } -/** Find the script `fltk-config` that most closely relates to this version of FLUID. - This is not implemented yet. +/** + Replace all occurrences of a macro with the given content. + + \param[inout] cmd buffer holding the command (must have enough space) + \param[in] cmd_size size of the command buffer + \param[in] macro the macro string to replace (e.g., "@BASENAME@") + \param[in] content the replacement string */ -//static void find_fltk_config() { -// -//} +static void expand_macro(char *cmd, int cmd_size, const char *macro, const char *content) { + char *pos; + int macro_len; + int content_len; + int tail_len; + + if (!cmd || !macro || !content) return; + macro_len = (int)strlen(macro); + content_len = (int)strlen(content); -static void expand_macro(std::string &cmd, const std::string ¯o, const std::string &content) { - for (int i=0;;) { - i = (int)cmd.find(macro, i); - if (i==(int)std::string::npos) break; - cmd.replace(i, macro.size(), content); + while ((pos = strstr(cmd, macro)) != 0) { + tail_len = (int)strlen(pos + macro_len); + if ((pos - cmd) + content_len + tail_len >= cmd_size - 1) { + // Not enough space, truncate + break; + } + memmove(pos + content_len, pos + macro_len, tail_len + 1); + memcpy(pos, content, content_len); } } -static void expand_macros(std::string &cmd) { - expand_macro(cmd, "@BASENAME@", Fluid.proj.basename()); - expand_macro(cmd, "@PROJECTFILE_PATH@", Fluid.proj.projectfile_path()); - expand_macro(cmd, "@PROJECTFILE_NAME@", Fluid.proj.projectfile_name()); - expand_macro(cmd, "@CODEFILE_PATH@", Fluid.proj.codefile_path()); - expand_macro(cmd, "@CODEFILE_NAME@", Fluid.proj.codefile_name()); - expand_macro(cmd, "@HEADERFILE_PATH@", Fluid.proj.headerfile_path()); - expand_macro(cmd, "@HEADERFILE_NAME@", Fluid.proj.headerfile_name()); - expand_macro(cmd, "@TEXTFILE_PATH@", Fluid.proj.stringsfile_path()); - expand_macro(cmd, "@TEXTFILE_NAME@", Fluid.proj.stringsfile_name()); -// TODO: implement finding the script `fltk-config` for all platforms -// if (cmd.find("@FLTK_CONFIG@") != std::string::npos) { -// find_fltk_config(); -// expand_macro(cmd, "@FLTK_CONFIG@", fltk_config_cmd.c_str()); -// } - if (cmd.find("@TMPDIR@") != std::string::npos) - expand_macro(cmd, "@TMPDIR@", Fluid.get_tmpdir()); +/** + Expand all known macros in the command string. + + \param[inout] cmd buffer holding the command + \param[in] cmd_size size of the command buffer + */ +static void expand_macros(char *cmd, int cmd_size) { + char buf[FL_PATH_MAX]; + + Fluid.proj.basename(buf, FL_PATH_MAX); + expand_macro(cmd, cmd_size, "@BASENAME@", buf); + + Fluid.proj.projectfile_path(buf, FL_PATH_MAX); + expand_macro(cmd, cmd_size, "@PROJECTFILE_PATH@", buf); + + { + const char *name = Fluid.proj.projectfile_name(); + expand_macro(cmd, cmd_size, "@PROJECTFILE_NAME@", name ? name : ""); + } + + Fluid.proj.codefile_path(buf, FL_PATH_MAX); + expand_macro(cmd, cmd_size, "@CODEFILE_PATH@", buf); + + Fluid.proj.codefile_name(buf, FL_PATH_MAX); + expand_macro(cmd, cmd_size, "@CODEFILE_NAME@", buf); + + Fluid.proj.headerfile_path(buf, FL_PATH_MAX); + expand_macro(cmd, cmd_size, "@HEADERFILE_PATH@", buf); + + Fluid.proj.headerfile_name(buf, FL_PATH_MAX); + expand_macro(cmd, cmd_size, "@HEADERFILE_NAME@", buf); + + Fluid.proj.stringsfile_path(buf, FL_PATH_MAX); + expand_macro(cmd, cmd_size, "@TEXTFILE_PATH@", buf); + + Fluid.proj.stringsfile_name(buf, FL_PATH_MAX); + expand_macro(cmd, cmd_size, "@TEXTFILE_NAME@", buf); + + if (strstr(cmd, "@TMPDIR@") != 0) { + const char *tmpdir = Fluid.get_tmpdir(); + expand_macro(cmd, cmd_size, "@TMPDIR@", tmpdir ? tmpdir : ""); + } } /** @@ -374,22 +327,26 @@ void show_terminal_window() { shell_run_window->show(); } +#define SHELL_CMD_BUF_SIZE 4096 + /** Prepare for and run a shell command. \param[in] cmd the command that is sent to `/bin/sh -c ...` or `cmd.exe` on Windows machines \param[in] flags various flags in preparation of the command */ -void run_shell_command(const std::string &cmd, int flags) { - if (cmd.empty()) { +void run_shell_command(const char *cmd, int flags) { + char expanded_cmd[SHELL_CMD_BUF_SIZE]; + + if (!cmd || !cmd[0]) { fl_alert("No shell command entered!"); return; } if (!prepare_shell_command(flags)) return; - std::string expanded_cmd = cmd; - expand_macros(expanded_cmd); + strlcpy(expanded_cmd, cmd, sizeof(expanded_cmd)); + expand_macros(expanded_cmd, sizeof(expanded_cmd)); if ( ((flags & Fd_Shell_Command::DONT_SHOW_TERMINAL) == 0) && (!shell_run_window->visible())) @@ -403,10 +360,10 @@ void run_shell_command(const std::string &cmd, int flags) { if (flags & Fd_Shell_Command::CLEAR_HISTORY) shell_run_terminal->printf("\033[3J"); shell_run_terminal->scrollbar->value(0); - shell_run_terminal->printf("\033[0;32m%s\033[0m\n", expanded_cmd.c_str()); - shell_run_window->label(expanded_cmd.c_str()); + shell_run_terminal->printf("\033[0;32m%s\033[0m\n", expanded_cmd); + shell_run_window->label(expanded_cmd); - if (s_proc.popen((char *)expanded_cmd.c_str()) == nullptr) { + if (s_proc.popen(expanded_cmd, "r") == 0) { shell_run_terminal->printf("\033[1;31mUnable to run shell command: %s\033[0m\n", strerror(errno)); shell_run_window->label("FLUID Shell"); @@ -421,15 +378,24 @@ void run_shell_command(const std::string &cmd, int flags) { Fl::add_fd(s_proc.get_fileno(), shell_pipe_cb); } +// Helper to duplicate a string safely +static char *dup_str(const char *s) { + return s ? strdup(s) : 0; +} + /** Create an empty shell command structure. */ Fd_Shell_Command::Fd_Shell_Command() -: shortcut(0), +: name(0), + label(0), + shortcut(0), storage(FLD_TOOL_STORE_USER), condition(0), + condition_data(0), + command(0), flags(0), - shell_menu_item_(nullptr) + shell_menu_item_(0) { } @@ -439,75 +405,94 @@ Fd_Shell_Command::Fd_Shell_Command() \param[in] rhs copy from this prototype */ Fd_Shell_Command::Fd_Shell_Command(const Fd_Shell_Command *rhs) -: name(rhs->name), - label(rhs->label), +: name(dup_str(rhs->name)), + label(dup_str(rhs->label)), shortcut(rhs->shortcut), storage(rhs->storage), condition(rhs->condition), - condition_data(rhs->condition_data), - command(rhs->command), + condition_data(dup_str(rhs->condition_data)), + command(dup_str(rhs->command)), flags(rhs->flags), - shell_menu_item_(nullptr) + shell_menu_item_(0) { } /** Create a default storage for a shell command and how it is accessible in FLUID. - \param[in] name is used as a stand-in for the command name and label + \param[in] in_name is used as a stand-in for the command name and label */ -Fd_Shell_Command::Fd_Shell_Command(const std::string &in_name) -: name(in_name), - label(in_name), +Fd_Shell_Command::Fd_Shell_Command(const char *in_name) +: name(dup_str(in_name)), + label(dup_str(in_name)), shortcut(0), storage(FLD_TOOL_STORE_USER), condition(Fd_Shell_Command::ALWAYS), - command("echo \"Hello, FLUID!\""), + condition_data(0), + command(strdup("echo \"Hello, FLUID!\"")), flags(Fd_Shell_Command::SAVE_PROJECT|Fd_Shell_Command::SAVE_SOURCECODE), - shell_menu_item_(nullptr) + shell_menu_item_(0) { } /** Create a storage for a shell command and how it is accessible in FLUID. - - \param[in] in_name name of this command in the command list in the settings panel - \param[in] in_label label text in the main pulldown menu - \param[in] in_shortcut a keyboard shortcut that will also appear in the main menu - \param[in] in_storage storage location for this command - \param[in] in_condition commands can be hidden for certain platforms by setting a condition - \param[in] in_condition_data more details for future conditions, i.e. per user, per host, etc. - \param[in] in_command the shell command that we want to run - \param[in] in_flags some flags to tell FLUID to save the project, code, or strings before running the command - */ -Fd_Shell_Command::Fd_Shell_Command(const std::string &in_name, - const std::string &in_label, + */ +Fd_Shell_Command::Fd_Shell_Command(const char *in_name, + const char *in_label, Fl_Shortcut in_shortcut, fld::Tool_Store in_storage, int in_condition, - const std::string &in_condition_data, - const std::string &in_command, + const char *in_condition_data, + const char *in_command, int in_flags) -: name(in_name), - label(in_label), +: name(dup_str(in_name)), + label(dup_str(in_label)), shortcut(in_shortcut), storage(in_storage), condition(in_condition), - condition_data(in_condition_data), - command(in_command), + condition_data(dup_str(in_condition_data)), + command(dup_str(in_command)), flags(in_flags), - shell_menu_item_(nullptr) + shell_menu_item_(0) { } /** - Run this command now. + Destructor - free all allocated strings. + */ +Fd_Shell_Command::~Fd_Shell_Command() { + if (name) free(name); + if (label) free(label); + if (condition_data) free(condition_data); + if (command) free(command); +} + +void Fd_Shell_Command::set_name(const char *s) { + if (name) free(name); + name = dup_str(s); +} + +void Fd_Shell_Command::set_label(const char *s) { + if (label) free(label); + label = dup_str(s); +} + +void Fd_Shell_Command::set_condition_data(const char *s) { + if (condition_data) free(condition_data); + condition_data = dup_str(s); +} + +void Fd_Shell_Command::set_command(const char *s) { + if (command) free(command); + command = dup_str(s); +} - Will open the Shell Panel and execute the command if no other command is - currently running. +/** + Run this command now. */ void Fd_Shell_Command::run() { - if (!command.empty()) + if (command && command[0]) run_shell_command(command, flags); } @@ -516,9 +501,9 @@ void Fd_Shell_Command::run() { */ void Fd_Shell_Command::update_shell_menu() { if (shell_menu_item_) { - const char *old_label = shell_menu_item_->label(); // can be nullptr - const char *new_label = label.c_str(); // never nullptr - if (!old_label || (old_label && strcmp(old_label, new_label))) { + const char *old_label = shell_menu_item_->label(); // can be 0 + const char *new_label = label ? label : ""; + if (!old_label || strcmp(old_label, new_label)) { if (old_label) ::free((void*)old_label); shell_menu_item_->label(fl_strdup(new_label)); } @@ -529,66 +514,75 @@ void Fd_Shell_Command::update_shell_menu() { /** Check if the set condition is met. - \return true if this command appears in the main menu + \return 1 if this command appears in the main menu */ -bool Fd_Shell_Command::is_active() { +int Fd_Shell_Command::is_active() { switch (condition) { - case ALWAYS: return true; - case NEVER: return false; + case ALWAYS: return 1; + case NEVER: return 0; #ifdef _WIN32 - case MAC_ONLY: return false; - case UX_ONLY: return false; - case WIN_ONLY: return true; - case MAC_AND_UX_ONLY: return false; + case MAC_ONLY: return 0; + case UX_ONLY: return 0; + case WIN_ONLY: return 1; + case MAC_AND_UX_ONLY: return 0; #elif defined(__APPLE__) - case MAC_ONLY: return true; - case UX_ONLY: return false; - case WIN_ONLY: return false; - case MAC_AND_UX_ONLY: return true; + case MAC_ONLY: return 1; + case UX_ONLY: return 0; + case WIN_ONLY: return 0; + case MAC_AND_UX_ONLY: return 1; #else - case MAC_ONLY: return false; - case UX_ONLY: return true; - case WIN_ONLY: return false; - case MAC_AND_UX_ONLY: return true; + case MAC_ONLY: return 0; + case UX_ONLY: return 1; + case WIN_ONLY: return 0; + case MAC_AND_UX_ONLY: return 1; #endif - case USER_ONLY: return false; // TODO: get user name - case HOST_ONLY: return false; // TODO: get host name + case USER_ONLY: return 0; // TODO: get user name + case HOST_ONLY: return 0; // TODO: get host name case ENV_ONLY: { - const char *value = fl_getenv(condition_data.c_str()); - if (value && *value) return true; - return false; + const char *value = condition_data ? fl_getenv(condition_data) : 0; + if (value && *value) return 1; + return 0; } } - return false; + return 0; } void Fd_Shell_Command::read(Fl_Preferences &prefs) { int tmp; char *str_ptr = 0; prefs.get("name", str_ptr, ""); - if (str_ptr) { name = str_ptr; free(str_ptr); str_ptr = 0; } + set_name(str_ptr); + if (str_ptr) { free(str_ptr); str_ptr = 0; } + prefs.get("label", str_ptr, ""); - if (str_ptr) { label = str_ptr; free(str_ptr); str_ptr = 0; } + set_label(str_ptr); + if (str_ptr) { free(str_ptr); str_ptr = 0; } + prefs.get("shortcut", tmp, 0); shortcut = (Fl_Shortcut)tmp; prefs.get("storage", tmp, -1); if (tmp != -1) storage = (fld::Tool_Store)tmp; prefs.get("condition", condition, ALWAYS); + prefs.get("condition_data", str_ptr, ""); - if (str_ptr) { condition_data = str_ptr; free(str_ptr); str_ptr = 0; } + set_condition_data(str_ptr); + if (str_ptr) { free(str_ptr); str_ptr = 0; } + prefs.get("command", str_ptr, ""); - if (str_ptr) { command = str_ptr; free(str_ptr); str_ptr = 0; } + set_command(str_ptr); + if (str_ptr) { free(str_ptr); str_ptr = 0; } + prefs.get("flags", flags, 0); } -void Fd_Shell_Command::write(Fl_Preferences &prefs, bool save_location) { - prefs.set("name", name.c_str()); - prefs.set("label", label.c_str()); +void Fd_Shell_Command::write(Fl_Preferences &prefs, int save_location) { + prefs.set("name", name ? name : ""); + prefs.set("label", label ? label : ""); if (shortcut != 0) prefs.set("shortcut", (int)shortcut); if (save_location) prefs.set("storage", (int)storage); if (condition != ALWAYS) prefs.set("condition", condition); - if (!condition_data.empty()) prefs.set("condition_data", condition_data.c_str()); - if (!command.empty()) prefs.set("command", command.c_str()); + if (condition_data && condition_data[0]) prefs.set("condition_data", condition_data); + if (command && command[0]) prefs.set("command", command); if (flags != 0) prefs.set("flags", flags); } @@ -600,17 +594,17 @@ void Fd_Shell_Command::read(class fld::io::Project_Reader *in) { c = in->read_word(1); if (strcmp(c, "}")==0) break; // end of command list else if (strcmp(c, "name")==0) - name = in->read_word(); + set_name(in->read_word()); else if (strcmp(c, "label")==0) - label = in->read_word(); + set_label(in->read_word()); else if (strcmp(c, "shortcut")==0) shortcut = in->read_int(); else if (strcmp(c, "condition")==0) condition = in->read_int(); else if (strcmp(c, "condition_data")==0) - condition_data = in->read_word(); + set_condition_data(in->read_word()); else if (strcmp(c, "command")==0) - command = in->read_word(); + set_command(in->read_word()); else if (strcmp(c, "flags")==0) flags = in->read_int(); else @@ -620,14 +614,14 @@ void Fd_Shell_Command::read(class fld::io::Project_Reader *in) { void Fd_Shell_Command::write(class fld::io::Project_Writer *out) { out->write_string("\n command {"); - out->write_string("\n name "); out->write_word(name); - out->write_string("\n label "); out->write_word(label); + out->write_string("\n name "); out->write_word(name ? name : ""); + out->write_string("\n label "); out->write_word(label ? label : ""); if (shortcut) out->write_string("\n shortcut %d", shortcut); if (condition) out->write_string("\n condition %d", condition); - if (!condition_data.empty()) { + if (condition_data && condition_data[0]) { out->write_string("\n condition_data "); out->write_word(condition_data); } - if (!command.empty()) { + if (command && command[0]) { out->write_string("\n command "); out->write_word(command); } if (flags) out->write_string("\n flags %d", flags); @@ -639,6 +633,10 @@ void Fd_Shell_Command::write(class fld::io::Project_Writer *out) { Manage a list of shell commands and their parameters. */ Fd_Shell_Command_List::Fd_Shell_Command_List() +: list(0), + list_size(0), + list_capacity(0), + shell_menu_(0) { } @@ -664,13 +662,14 @@ Fd_Shell_Command *Fd_Shell_Command_List::at(int index) const { */ void Fd_Shell_Command_List::clear() { if (list) { - for (int i=0; i=0; i--) { + int i; + for (i=list_size-1; i>=0; i--) { if (list[i]->storage == storage) { remove(i); } @@ -689,6 +689,7 @@ void Fd_Shell_Command_List::clear(fld::Tool_Store storage) { Read shell configuration from a preferences group. */ void Fd_Shell_Command_List::read(Fl_Preferences &prefs, fld::Tool_Store storage) { + int i, n; // import the old shell commands from previous user settings if (&Fluid.preferences == &prefs) { int version; @@ -697,12 +698,12 @@ void Fd_Shell_Command_List::read(Fl_Preferences &prefs, fld::Tool_Store storage) int save_fl, save_code, save_strings; Fd_Shell_Command *cmd = new Fd_Shell_Command(); cmd->storage = FLD_TOOL_STORE_USER; - cmd->name = "Sample Shell Command"; - cmd->label = "Sample Shell Command"; + cmd->set_name("Sample Shell Command"); + cmd->set_label("Sample Shell Command"); cmd->shortcut = FL_ALT+'g'; char *cmd_str = 0; Fluid.preferences.get("shell_command", cmd_str, "echo \"Sample Shell Command\""); - if (cmd_str) { cmd->command = cmd_str; free(cmd_str); } + if (cmd_str) { cmd->set_command(cmd_str); free(cmd_str); } Fluid.preferences.get("shell_savefl", save_fl, 1); Fluid.preferences.get("shell_writecode", save_code, 1); Fluid.preferences.get("shell_writemsgs", save_strings, 0); @@ -715,8 +716,8 @@ void Fd_Shell_Command_List::read(Fl_Preferences &prefs, fld::Tool_Store storage) prefs.set("shell_commands_version", version); } Fl_Preferences shell_commands(prefs, "shell_commands"); - int n = shell_commands.groups(); - for (int i=0; istorage = FLD_TOOL_STORE_USER; @@ -729,13 +730,14 @@ void Fd_Shell_Command_List::read(Fl_Preferences &prefs, fld::Tool_Store storage) Write shell configuration to a preferences group. */ void Fd_Shell_Command_List::write(Fl_Preferences &prefs, fld::Tool_Store storage) { + int i, index; Fl_Preferences shell_commands(prefs, "shell_commands"); shell_commands.delete_all_groups(); - int index = 0; - for (int i=0; istorage == FLD_TOOL_STORE_USER) { Fl_Preferences cmd(shell_commands, Fl_Preferences::Name(index++)); - list[i]->write(cmd); + list[i]->write(cmd, 0); } } } @@ -764,14 +766,14 @@ void Fd_Shell_Command_List::read(fld::io::Project_Reader *in) { Write shell configuration to a project file. */ void Fd_Shell_Command_List::write(fld::io::Project_Writer *out) { - int n_in_project_file = 0; - for (int i=0; istorage == FLD_TOOL_STORE_PROJECT) n_in_project_file++; } if (n_in_project_file > 0) { out->write_string("\nshell_commands {"); - for (int i=0; istorage == FLD_TOOL_STORE_PROJECT) list[i]->write(out); } @@ -842,12 +844,14 @@ void menu_shell_customize_cb(Fl_Widget*, void*) { Rebuild the entire shell submenu from scratch and replace the old menu. */ void Fd_Shell_Command_List::rebuild_shell_menu() { - static Fl_Menu_Item *shell_submenu = nullptr; + static Fl_Menu_Item *shell_submenu = 0; + int i, j, num_active_items; + if (!shell_submenu) shell_submenu = (Fl_Menu_Item*)Fluid.main_menubar->find_item(menu_marker); - int i, j, num_active_items = 0; // count the active commands + num_active_items = 0; for (i=0; iis_active()) num_active_items++; } @@ -875,9 +879,9 @@ void Fd_Shell_Command_List::rebuild_shell_menu() { // free all resources from the old menu if (mi_old && (mi_old != default_menu)) { for (i=0; ; i++) { - const char *label = mi_old[i].label(); - if (!label) break; - ::free((void*)label); + const char *lbl = mi_old[i].label(); + if (!lbl) break; + ::free((void*)lbl); } ::free(mi_old); } @@ -896,7 +900,7 @@ void Fd_Shell_Command_List::update_settings_dialog() { */ Fl_Menu_Item Fd_Shell_Command_List::default_menu[] = { { "Customize...", FL_ALT+'x', menu_shell_customize_cb }, - { nullptr } + { 0 } }; /** @@ -908,12 +912,11 @@ void Fd_Shell_Command_List::menu_marker(Fl_Widget*, void*) { /** Export all selected shell commands to an external file. - - Verify that g_shell_config and w_settings_shell_list are not nullptr. Open a - file chooser and export all items that are selected in w_settings_shell_list - into an external file. */ void Fd_Shell_Command_List::export_selected() { + char path[FL_PATH_MAX]; + char preset[FL_PATH_MAX]; + if (!g_shell_config || (g_shell_config->list_size == 0)) return; if (!w_settings_shell_list) return; @@ -921,28 +924,37 @@ void Fd_Shell_Command_List::export_selected() { dialog.title("Export selected shell commands:"); dialog.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); dialog.filter("FLUID Files\t*.flcmd\n"); - dialog.directory(Fluid.proj.projectfile_path().c_str()); - dialog.preset_file((Fluid.proj.basename() + ".flcmd").c_str()); + + Fluid.proj.projectfile_path(path, FL_PATH_MAX); + dialog.directory(path); + + Fluid.proj.basename(preset, FL_PATH_MAX); + strlcat(preset, ".flcmd", FL_PATH_MAX); + dialog.preset_file(preset); + if (dialog.show() != 0) return; - Fl_Preferences file(dialog.filename(), "flcmd.fluid.fltk.org", nullptr, (Fl_Preferences::Root)(Fl_Preferences::C_LOCALE|Fl_Preferences::CLEAR)); + Fl_Preferences file(dialog.filename(), "flcmd.fluid.fltk.org", 0, (Fl_Preferences::Root)(Fl_Preferences::C_LOCALE|Fl_Preferences::CLEAR)); Fl_Preferences shell_commands(file, "shell_commands"); - int i, index = 0, n = w_settings_shell_list->size(); + int i, index, n; + index = 0; + n = w_settings_shell_list->size(); for (i = 0; i < n; i++) { if (w_settings_shell_list->selected(i+1)) { Fl_Preferences cmd(shell_commands, Fl_Preferences::Name(index++)); - g_shell_config->list[i]->write(cmd, true); + g_shell_config->list[i]->write(cmd, 1); } } } /** Import shell commands from an external file and add them to the list. - - Verify that g_shell_config and w_settings_shell_list are not nullptr. Open a - file chooser and import all items. */ void Fd_Shell_Command_List::import_from_file() { + char path[FL_PATH_MAX]; + char preset[FL_PATH_MAX]; + int i, n; + if (!g_shell_config || (g_shell_config->list_size == 0)) return; if (!w_settings_shell_list) return; @@ -950,13 +962,19 @@ void Fd_Shell_Command_List::import_from_file() { dialog.title("Import shell commands:"); dialog.type(Fl_Native_File_Chooser::BROWSE_FILE); dialog.filter("FLUID Files\t*.flcmd\n"); - dialog.directory(Fluid.proj.projectfile_path().c_str()); - dialog.preset_file((Fluid.proj.basename() + ".flcmd").c_str()); + + Fluid.proj.projectfile_path(path, FL_PATH_MAX); + dialog.directory(path); + + Fluid.proj.basename(preset, FL_PATH_MAX); + strlcat(preset, ".flcmd", FL_PATH_MAX); + dialog.preset_file(preset); + if (dialog.show() != 0) return; - Fl_Preferences file(dialog.filename(), "flcmd.fluid.fltk.org", nullptr, Fl_Preferences::C_LOCALE); + Fl_Preferences file(dialog.filename(), "flcmd.fluid.fltk.org", 0, Fl_Preferences::C_LOCALE); Fl_Preferences shell_commands(file, "shell_commands"); - int i, n = shell_commands.groups(); + n = shell_commands.groups(); for (i = 0; i < n; i++) { Fl_Preferences cmd_prefs(shell_commands, Fl_Preferences::Name(i)); Fd_Shell_Command *cmd = new Fd_Shell_Command(); @@ -973,5 +991,4 @@ void Fd_Shell_Command_List::import_from_file() { /** A pointer to the list of shell commands if we are not in batch mode. */ -Fd_Shell_Command_List *g_shell_config = nullptr; - +Fd_Shell_Command_List *g_shell_config = 0; diff --git a/fluid/app/shell_command.h b/fluid/app/shell_command.h index b9e68ca15..716a87349 100644 --- a/fluid/app/shell_command.h +++ b/fluid/app/shell_command.h @@ -23,7 +23,6 @@ #include #include -#include #if defined(_WIN32) && !defined(__CYGWIN__) # include # include @@ -49,8 +48,8 @@ class Fl_Widget; class Fl_Preferences; void show_terminal_window(); -void run_shell_command(const std::string &cmd, int flags); -bool shell_command_running(void); +void run_shell_command(const char *cmd, int flags); +int shell_command_running(void); class Fl_Process { @@ -58,7 +57,7 @@ public: Fl_Process(); ~Fl_Process(); - FILE *popen(const char *cmd, const char *mode="r"); + FILE *popen(const char *cmd, const char *mode); int close(); FILE * desc() const; @@ -73,7 +72,7 @@ protected: PROCESS_INFORMATION pi; STARTUPINFO si; - static bool createPipe(HANDLE * h, BOOL bInheritHnd=TRUE); + static int createPipe(HANDLE * h, BOOL bInheritHnd); private: FILE * freeHandles(); @@ -81,7 +80,7 @@ private: #endif protected: - FILE * _fpt = nullptr; + FILE * _fpt; }; @@ -90,42 +89,51 @@ public: enum { ALWAYS, NEVER, MAC_ONLY, UX_ONLY, WIN_ONLY, MAC_AND_UX_ONLY, USER_ONLY, HOST_ONLY, ENV_ONLY }; // conditions enum { SAVE_PROJECT = 1, SAVE_SOURCECODE = 2, SAVE_STRINGS = 4, SAVE_ALL = 7, DONT_SHOW_TERMINAL = 8, CLEAR_TERMINAL = 16, CLEAR_HISTORY = 32 }; // flags + + char *name; + char *label; + Fl_Shortcut shortcut; + fld::Tool_Store storage; + int condition; + char *condition_data; + char *command; + int flags; + Fl_Menu_Item *shell_menu_item_; + Fd_Shell_Command(); Fd_Shell_Command(const Fd_Shell_Command *rhs); - Fd_Shell_Command(const std::string &in_name); - Fd_Shell_Command(const std::string &in_name, - const std::string &in_label, + Fd_Shell_Command(const char *in_name); + Fd_Shell_Command(const char *in_name, + const char *in_label, Fl_Shortcut in_shortcut, fld::Tool_Store in_storage, int in_condition, - const std::string &in_condition_data, - const std::string &in_command, + const char *in_condition_data, + const char *in_command, int in_flags); - std::string name { }; - std::string label { }; - Fl_Shortcut shortcut = 0; - fld::Tool_Store storage = FLD_TOOL_STORE_USER; - int condition = ALWAYS; // always, hide, windows only, linux only, mac only, user, machine - std::string condition_data { }; // user name, machine name - std::string command { }; - int flags = 0; // save_project, save_code, save_string, ... - Fl_Menu_Item *shell_menu_item_; + ~Fd_Shell_Command(); + + void set_name(const char *s); + void set_label(const char *s); + void set_condition_data(const char *s); + void set_command(const char *s); + void run(); void read(Fl_Preferences &prefs); - void write(Fl_Preferences &prefs, bool save_location = false); + void write(Fl_Preferences &prefs, int save_location); void read(class fld::io::Project_Reader*); void write(class fld::io::Project_Writer*); void update_shell_menu(); - bool is_active(); + int is_active(); }; class Fd_Shell_Command_List { public: - Fd_Shell_Command **list = nullptr; - int list_size = 0; - int list_capacity = 0; - Fl_Menu_Item *shell_menu_ = nullptr; + Fd_Shell_Command **list; + int list_size; + int list_capacity; + Fl_Menu_Item *shell_menu_; public: Fd_Shell_Command_List(); ~Fd_Shell_Command_List(); @@ -135,10 +143,6 @@ public: void remove(int index); void clear(); void clear(fld::Tool_Store store); -// void move_up(); -// void move_down(); -// int load(const std::string &filename); -// int save(const std::string &filename); void read(Fl_Preferences &prefs, fld::Tool_Store storage); void write(Fl_Preferences &prefs, fld::Tool_Store storage); void read(class fld::io::Project_Reader*); diff --git a/fluid/app/templates.cxx b/fluid/app/templates.cxx index 09fdc0220..8b9b69f2a 100644 --- a/fluid/app/templates.cxx +++ b/fluid/app/templates.cxx @@ -93,7 +93,7 @@ void fld::app::save_template() { if (!fl_access(filename, 0)) { if (fl_choice("The template \"%s\" already exists.\n" "Do you want to replace it?", "Cancel", - "Replace", nullptr, c) == 0) return; + "Replace", 0, c) == 0) return; } if (!fld::io::write_file(Fluid.proj, filename)) { @@ -117,7 +117,7 @@ void fld::app::save_template() { uchar *pixels; int w, h; - if ((pixels = wt->read_image(w, h)) == nullptr) return; + if ((pixels = wt->read_image(w, h)) == 0) return; // Save to a PNG file... strcpy(ext, ".png"); -- cgit v1.2.3