Fluid: fix class prefix user input check.

This commit is contained in:
Matthias Melcher 2025-12-06 02:29:57 +01:00
parent b2746ad286
commit 5e7ed2f653
6 changed files with 86 additions and 44 deletions

View File

@ -320,11 +320,10 @@ Node *Project_Reader::read_children(Node *p, int merge, Strategy strategy, char
c = read_word(1); c = read_word(1);
// There can actually be two keywords here. The first one used to be a // There can actually be two keywords here. The first one used to be a
// "prefix" in Fluid < 1.5.0, but is no longer supported. So if we still // "prefix", i.e. class attributes.
// find the prefix in files, it will simply be prefixed to the name.
if (strcmp(c,"{") && t->is_class()) { // <prefix> <name> if (strcmp(c,"{") && t->is_class()) { // <prefix> <name>
std::string tmp = std::string {t->name() } + " " + c; ((Class_Node*)t)->prefix( t->name() );
t->name(tmp.c_str()); t->name( c );
c = read_word(1); c = read_word(1);
} }

View File

@ -1514,8 +1514,7 @@ Class_Node Class_Node::prototype;
Class_Node::Class_Node() : Class_Node::Class_Node() :
Node(), Node(),
subclass_of(nullptr), subclass_of(nullptr),
public_(1), public_(1)
class_prefix(nullptr)
{ } { }
/** /**
@ -1524,8 +1523,6 @@ Class_Node::Class_Node() :
Class_Node::~Class_Node() { Class_Node::~Class_Node() {
if (subclass_of) if (subclass_of)
free((void*)subclass_of); free((void*)subclass_of);
if (class_prefix)
free((void*)class_prefix);
} }
/** /**
@ -1535,14 +1532,6 @@ int Class_Node::is_public() const {
return public_; return public_;
} }
/**
Set the prefixx string.
*/
void Class_Node::prefix(const char*p) {
free((void*) class_prefix);
class_prefix=fl_strdup(p ? p : "" );
}
/** /**
Make a new class node. Make a new class node.
\param[in] strategy add after current or as last child \param[in] strategy add after current or as last child
@ -1559,7 +1548,7 @@ Node *Class_Node::make(Strategy strategy) {
} }
Class_Node *o = new Class_Node(); Class_Node *o = new Class_Node();
o->name("UserInterface"); o->name("UserInterface");
o->class_prefix = nullptr; o->prefix("");
o->subclass_of = nullptr; o->subclass_of = nullptr;
o->public_ = 1; o->public_ = 1;
o->add(anchor, strategy); o->add(anchor, strategy);
@ -1615,8 +1604,8 @@ void Class_Node::write_code1(fld::io::Code_Writer& f) {
write_public_state = 0; write_public_state = 0;
f.write_h("\n"); f.write_h("\n");
write_comment_h(f); write_comment_h(f);
if (prefix() && strlen(prefix())) if (!prefix().empty())
f.write_h("class %s %s ", prefix(), name()); f.write_h("class %s %s ", prefix().c_str(), name());
else else
f.write_h("class %s ", name()); f.write_h("class %s ", name());
if (subclass_of) f.write_h(": %s ", subclass_of); if (subclass_of) f.write_h(": %s ", subclass_of);

View File

@ -34,6 +34,8 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <string>
extern class Class_Node *current_class; extern class Class_Node *current_class;
int has_toplevel_function(const char *rtype, const char *sig); int has_toplevel_function(const char *rtype, const char *sig);
@ -271,7 +273,7 @@ public:
private: private:
const char* subclass_of; const char* subclass_of;
char public_; char public_;
const char* class_prefix; std::string prefix_;
public: public:
Class_Node(); Class_Node();
~Class_Node(); ~Class_Node();
@ -298,8 +300,10 @@ public:
void visibility(char v) { public_ = v; } void visibility(char v) { public_ = v; }
// class prefix attribute access // class prefix attribute access
void prefix(const char* p); /** Set the text between `class` and the class name */
const char* prefix() const {return class_prefix;} void prefix(const std::string& p) { prefix_ = p; }
/** Get the text between `class` and the class name */
std::string prefix() const { return prefix_; }
}; };
#endif // FLUID_NODES_FUNCTION_NODE_H #endif // FLUID_NODES_FUNCTION_NODE_H

View File

@ -889,9 +889,9 @@ void Node::write(fld::io::Project_Writer &f) {
f.write_word(type_name()); f.write_word(type_name());
if (is_class()) { if (is_class()) {
const char * p = ((Class_Node*)this)->prefix(); auto p = ((Class_Node*)this)->prefix();
if (p && strlen(p)) if (!p.empty())
f.write_word(p); f.write_word(p.c_str());
} }
f.write_word(name()); f.write_word(name());

View File

@ -31,6 +31,7 @@
#include <FL/fl_ask.H> #include <FL/fl_ask.H>
#include <FL/Fl_Menu_Item.H> #include <FL/Fl_Menu_Item.H>
#include <FL/Fl_File_Chooser.H> #include <FL/Fl_File_Chooser.H>
#include <ctype.h>
#define ZERO_ENTRY 1000 #define ZERO_ENTRY 1000
extern const char* when_symbol_name(int n); extern const char* when_symbol_name(int n);
extern void set_whenmenu(int n); extern void set_whenmenu(int n);
@ -2636,11 +2637,10 @@ static void cb_Attribute(Fl_Input* o, void* v) {
Class_Node* nd = (Class_Node*)current_node; Class_Node* nd = (Class_Node*)current_node;
if (v == LOAD) { if (v == LOAD) {
o->value( nd->prefix() ); o->value( nd->prefix().c_str() );
} else { } else {
const char *nn = nd->prefix(); auto nn = nd->prefix();
if ( ( nn && (strcmp(nn, o->value()) != 0)) if (nn != o->value())
|| (!nn && (strcmp("", o->value()) != 0)) )
{ {
nd->prefix( o->value() ); nd->prefix( o->value() );
Fluid.proj.set_modflag(1); Fluid.proj.set_modflag(1);
@ -2657,13 +2657,37 @@ static void cb_Class(Fl_Input* o, void* v) {
o->value( nd->name() ); o->value( nd->name() );
} else { } else {
const char *nn = nd->name(); const char *nn = nd->name();
if ( ( nn && (strcmp(nn, o->value()) != 0)) char *nv = strdup( o->value() );
|| (!nn && (strcmp("", o->value()) != 0)) ) // There is an inconsistency in the project file reader, so this string
// must not coantain anything but alphanumeric and underscore characters.
char *s = (char*)nv;
char *d = (char*)nv;
while (*s) {
if (isalnum((unsigned char)*s) || *s == '_') {
*d++ = *s;
}
s++;
}
*d = 0;
// The class name must not be empty either
if (*nv == 0) {
free((void*)nv);
nv = strdup("MyClass");
}
// The class name may have changed, so update the widget
o->value( nv );
// Now copy the new name into the node if it changed
if ( ( nn && (strcmp(nn, nv) != 0))
|| (!nn && (strcmp("", nv) != 0)) )
{ {
nd->name( o->value() ); nd->name( nv );
Fluid.proj.set_modflag(1); Fluid.proj.set_modflag(1);
redraw_browser(); redraw_browser();
} }
// Don't forget to clean up
if (nv) {
free((void*)nv);
}
} }
} }
@ -3239,6 +3263,7 @@ Fl_Double_Window* make_widget_panel() {
widget_tabs->labelcolor(FL_BACKGROUND2_COLOR); widget_tabs->labelcolor(FL_BACKGROUND2_COLOR);
widget_tabs->callback((Fl_Callback*)cb_widget_tabs); widget_tabs->callback((Fl_Callback*)cb_widget_tabs);
widget_tabs->when(FL_WHEN_NEVER); widget_tabs->when(FL_WHEN_NEVER);
widget_tabs->hide();
{ wp_gui_tab = new Fl_Group(10, 30, 400, 330, "GUI"); { wp_gui_tab = new Fl_Group(10, 30, 400, 330, "GUI");
wp_gui_tab->labelsize(11); wp_gui_tab->labelsize(11);
wp_gui_tab->callback((Fl_Callback*)propagate_load); wp_gui_tab->callback((Fl_Callback*)propagate_load);
@ -4326,7 +4351,6 @@ Fl_Double_Window* make_widget_panel() {
class_tabs->labelsize(11); class_tabs->labelsize(11);
class_tabs->labelcolor(FL_WHITE); class_tabs->labelcolor(FL_WHITE);
class_tabs->callback((Fl_Callback*)cb_class_tabs); class_tabs->callback((Fl_Callback*)cb_class_tabs);
class_tabs->hide();
{ class_tabs_main = new Fl_Group(10, 30, 400, 330, "Class"); { class_tabs_main = new Fl_Group(10, 30, 400, 330, "Class");
class_tabs_main->labelsize(11); class_tabs_main->labelsize(11);
class_tabs_main->callback((Fl_Callback*)propagate_load); class_tabs_main->callback((Fl_Callback*)propagate_load);

View File

@ -80,6 +80,9 @@ decl {\#include <FL/Fl_Menu_Item.H>} {private global
decl {\#include <FL/Fl_File_Chooser.H>} {private global decl {\#include <FL/Fl_File_Chooser.H>} {private global
} }
decl {\#include <ctype.h>} {selected private global
}
decl {\#define ZERO_ENTRY 1000} {private global decl {\#define ZERO_ENTRY 1000} {private global
} }
@ -486,8 +489,8 @@ Function {make_widget_panel()} {
} { } {
Fl_Tabs widget_tabs { Fl_Tabs widget_tabs {
callback {if (current_widget) callback {if (current_widget)
propagate_load((Fl_Group *)o,v);} selected propagate_load((Fl_Group *)o,v);}
xywh {10 10 400 350} selection_color 12 labelsize 11 labelcolor 7 when 0 xywh {10 10 400 350} selection_color 12 labelsize 11 labelcolor 7 when 0 hide
code0 {o->show();} code0 {o->show();}
} { } {
Fl_Group wp_gui_tab { Fl_Group wp_gui_tab {
@ -2972,8 +2975,8 @@ if (v == LOAD) {
} }
Fl_Tabs class_tabs { Fl_Tabs class_tabs {
callback {if (current_node && current_node->is_a(Type::Class)) callback {if (current_node && current_node->is_a(Type::Class))
propagate_load((Fl_Group *)o,v);} propagate_load((Fl_Group *)o,v);} open
xywh {10 10 400 350} selection_color 12 labelsize 11 labelcolor 255 hide xywh {10 10 400 350} selection_color 12 labelsize 11 labelcolor 255
} { } {
Fl_Group class_tabs_main { Fl_Group class_tabs_main {
label Class label Class
@ -3032,11 +3035,10 @@ if (v == LOAD) {
Class_Node* nd = (Class_Node*)current_node; Class_Node* nd = (Class_Node*)current_node;
if (v == LOAD) { if (v == LOAD) {
o->value( nd->prefix() ); o->value( nd->prefix().c_str() );
} else { } else {
const char *nn = nd->prefix(); auto nn = nd->prefix();
if ( ( nn && (strcmp(nn, o->value()) != 0)) if (nn != o->value())
|| (!nn && (strcmp("", o->value()) != 0)) )
{ {
nd->prefix( o->value() ); nd->prefix( o->value() );
Fluid.proj.set_modflag(1); Fluid.proj.set_modflag(1);
@ -3054,13 +3056,37 @@ if (v == LOAD) {
o->value( nd->name() ); o->value( nd->name() );
} else { } else {
const char *nn = nd->name(); const char *nn = nd->name();
if ( ( nn && (strcmp(nn, o->value()) != 0)) char *nv = strdup( o->value() );
|| (!nn && (strcmp("", o->value()) != 0)) ) // There is an inconsistency in the project file reader, so this string
// must not coantain anything but alphanumeric and underscore characters.
char *s = (char*)nv;
char *d = (char*)nv;
while (*s) {
if (isalnum((unsigned char)*s) || *s == '_') {
*d++ = *s;
}
s++;
}
*d = 0;
// The class name must not be empty either
if (*nv == 0) {
free((void*)nv);
nv = strdup("MyClass");
}
// The class name may have changed, so update the widget
o->value( nv );
// Now copy the new name into the node if it changed
if ( ( nn && (strcmp(nn, nv) != 0))
|| (!nn && (strcmp("", nv) != 0)) )
{ {
nd->name( o->value() ); nd->name( nv );
Fluid.proj.set_modflag(1); Fluid.proj.set_modflag(1);
redraw_browser(); redraw_browser();
} }
// Don't forget to clean up
if (nv) {
free((void*)nv);
}
}} }}
tooltip {class name, must be a single C++ keyword} xywh {95 75 305 20} labelfont 1 labelsize 11 textfont 4 textsize 11 tooltip {class name, must be a single C++ keyword} xywh {95 75 305 20} labelfont 1 labelsize 11 textfont 4 textsize 11
} }