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);
// 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
// find the prefix in files, it will simply be prefixed to the name.
// "prefix", i.e. class attributes.
if (strcmp(c,"{") && t->is_class()) { // <prefix> <name>
std::string tmp = std::string {t->name() } + " " + c;
t->name(tmp.c_str());
((Class_Node*)t)->prefix( t->name() );
t->name( c );
c = read_word(1);
}

View File

@ -1514,8 +1514,7 @@ Class_Node Class_Node::prototype;
Class_Node::Class_Node() :
Node(),
subclass_of(nullptr),
public_(1),
class_prefix(nullptr)
public_(1)
{ }
/**
@ -1524,8 +1523,6 @@ Class_Node::Class_Node() :
Class_Node::~Class_Node() {
if (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_;
}
/**
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.
\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();
o->name("UserInterface");
o->class_prefix = nullptr;
o->prefix("");
o->subclass_of = nullptr;
o->public_ = 1;
o->add(anchor, strategy);
@ -1615,8 +1604,8 @@ void Class_Node::write_code1(fld::io::Code_Writer& f) {
write_public_state = 0;
f.write_h("\n");
write_comment_h(f);
if (prefix() && strlen(prefix()))
f.write_h("class %s %s ", prefix(), name());
if (!prefix().empty())
f.write_h("class %s %s ", prefix().c_str(), name());
else
f.write_h("class %s ", name());
if (subclass_of) f.write_h(": %s ", subclass_of);

View File

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

View File

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

View File

@ -31,6 +31,7 @@
#include <FL/fl_ask.H>
#include <FL/Fl_Menu_Item.H>
#include <FL/Fl_File_Chooser.H>
#include <ctype.h>
#define ZERO_ENTRY 1000
extern const char* when_symbol_name(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;
if (v == LOAD) {
o->value( nd->prefix() );
o->value( nd->prefix().c_str() );
} else {
const char *nn = nd->prefix();
if ( ( nn && (strcmp(nn, o->value()) != 0))
|| (!nn && (strcmp("", o->value()) != 0)) )
auto nn = nd->prefix();
if (nn != o->value())
{
nd->prefix( o->value() );
Fluid.proj.set_modflag(1);
@ -2657,13 +2657,37 @@ static void cb_Class(Fl_Input* o, void* v) {
o->value( nd->name() );
} else {
const char *nn = nd->name();
if ( ( nn && (strcmp(nn, o->value()) != 0))
|| (!nn && (strcmp("", o->value()) != 0)) )
char *nv = strdup( o->value() );
// 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);
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->callback((Fl_Callback*)cb_widget_tabs);
widget_tabs->when(FL_WHEN_NEVER);
widget_tabs->hide();
{ wp_gui_tab = new Fl_Group(10, 30, 400, 330, "GUI");
wp_gui_tab->labelsize(11);
wp_gui_tab->callback((Fl_Callback*)propagate_load);
@ -4326,7 +4351,6 @@ Fl_Double_Window* make_widget_panel() {
class_tabs->labelsize(11);
class_tabs->labelcolor(FL_WHITE);
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->labelsize(11);
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 <ctype.h>} {selected private global
}
decl {\#define ZERO_ENTRY 1000} {private global
}
@ -486,8 +489,8 @@ Function {make_widget_panel()} {
} {
Fl_Tabs widget_tabs {
callback {if (current_widget)
propagate_load((Fl_Group *)o,v);} selected
xywh {10 10 400 350} selection_color 12 labelsize 11 labelcolor 7 when 0
propagate_load((Fl_Group *)o,v);}
xywh {10 10 400 350} selection_color 12 labelsize 11 labelcolor 7 when 0 hide
code0 {o->show();}
} {
Fl_Group wp_gui_tab {
@ -2972,8 +2975,8 @@ if (v == LOAD) {
}
Fl_Tabs class_tabs {
callback {if (current_node && current_node->is_a(Type::Class))
propagate_load((Fl_Group *)o,v);}
xywh {10 10 400 350} selection_color 12 labelsize 11 labelcolor 255 hide
propagate_load((Fl_Group *)o,v);} open
xywh {10 10 400 350} selection_color 12 labelsize 11 labelcolor 255
} {
Fl_Group class_tabs_main {
label Class
@ -3032,11 +3035,10 @@ if (v == LOAD) {
Class_Node* nd = (Class_Node*)current_node;
if (v == LOAD) {
o->value( nd->prefix() );
o->value( nd->prefix().c_str() );
} else {
const char *nn = nd->prefix();
if ( ( nn && (strcmp(nn, o->value()) != 0))
|| (!nn && (strcmp("", o->value()) != 0)) )
auto nn = nd->prefix();
if (nn != o->value())
{
nd->prefix( o->value() );
Fluid.proj.set_modflag(1);
@ -3054,13 +3056,37 @@ if (v == LOAD) {
o->value( nd->name() );
} else {
const char *nn = nd->name();
if ( ( nn && (strcmp(nn, o->value()) != 0))
|| (!nn && (strcmp("", o->value()) != 0)) )
char *nv = strdup( o->value() );
// 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);
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
}