1 //
2 // "$Id: Fl_Function_Type.cxx 8786 2011-06-07 11:41:36Z manolo $"
3 //
4 // C function type code for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2011 by Bill Spitzak and others.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // Library General Public License for more details.
17 //
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 // USA.
22 //
23 // Please report all bugs and problems on the following page:
24 //
25 //     http://www.fltk.org/str.php
26 //
27 
28 #include <FL/Fl.H>
29 #include <FL/Fl_Preferences.H>
30 #include <FL/Fl_File_Chooser.H>
31 #include "Fl_Type.h"
32 #include <FL/fl_show_input.H>
33 #include <FL/Fl_File_Chooser.H>
34 #include "../src/flstring.h"
35 #include <stdio.h>
36 #include <stdlib.h>
37 
38 extern int i18n_type;
39 extern const char* i18n_include;
40 extern const char* i18n_function;
41 extern const char* i18n_file;
42 extern const char* i18n_set;
43 extern char i18n_program[];
44 
45 extern int compile_only;
46 
47 extern void redraw_browser();
48 extern void goto_source_dir();
49 extern void leave_source_dir();
50 
51 ////////////////////////////////////////////////////////////////
52 // quick check of any C code for legality, returns an error message
53 
54 static char buffer[128]; // for error messages
55 
56 // check a quoted string ending in either " or ' or >:
_q_check(const char * & c,int type)57 const char *_q_check(const char * & c, int type) {
58   for (;;) switch (*c++) {
59     case '\0':
60       sprintf(buffer,"missing %c",type);
61       return buffer;
62     case '\\':
63       if (*c) c++;
64       break;
65     default:
66       if (*(c-1) == type) return 0;
67   }
68 }
69 
70 // check normal code, match braces and parenthesis:
_c_check(const char * & c,int type)71 const char *_c_check(const char * & c, int type) {
72   const char *d;
73   for (;;) switch (*c++) {
74     case 0:
75       if (!type) return 0;
76       sprintf(buffer, "missing %c", type);
77       return buffer;
78     case '/':
79       // Skip comments as needed...
80       if (*c == '/') {
81         while (*c != '\n' && *c) c++;
82       } else if (*c == '*') {
83         c++;
84         while ((*c != '*' || c[1] != '/') && *c) c++;
85         if (*c == '*') c+=2;
86         else {
87           return "missing '*/'";
88         }
89       }
90       break;
91     case '#':
92       // treat cpp directives as a comment:
93       while (*c != '\n' && *c) c++;
94       break;
95     case '{':
96       if (type==')') goto UNEXPECTED;
97       d = _c_check(c,'}');
98       if (d) return d;
99       break;
100     case '(':
101       d = _c_check(c,')');
102       if (d) return d;
103       break;
104     case '\"':
105       d = _q_check(c,'\"');
106       if (d) return d;
107       break;
108     case '\'':
109       d = _q_check(c,'\'');
110       if (d) return d;
111       break;
112     case '}':
113     case ')':
114     UNEXPECTED:
115       if (type == *(c-1)) return 0;
116       sprintf(buffer, "unexpected %c", *(c-1));
117       return buffer;
118   }
119 }
120 
c_check(const char * c,int type)121 const char *c_check(const char *c, int type) {
122   return _c_check(c,type);
123 }
124 
125 ////////////////////////////////////////////////////////////////
126 
is_public() const127 int Fl_Function_Type::is_public() const {return public_;}
128 
make()129 Fl_Type *Fl_Function_Type::make() {
130   Fl_Type *p = Fl_Type::current;
131   while (p && !p->is_decl_block()) p = p->parent;
132   Fl_Function_Type *o = new Fl_Function_Type();
133   o->name("make_window()");
134   o->return_type = 0;
135   o->add(p);
136   o->factory = this;
137   o->public_ = 1;
138   o->cdecl_ = 0;
139   return o;
140 }
141 
write_properties()142 void Fl_Function_Type::write_properties() {
143   Fl_Type::write_properties();
144   switch (public_) {
145     case 0: write_string("private"); break;
146     case 2: write_string("protected"); break;
147   }
148   if (cdecl_) write_string("C");
149   if (return_type) {
150     write_string("return_type");
151     write_word(return_type);
152   }
153 }
154 
read_property(const char * c)155 void Fl_Function_Type::read_property(const char *c) {
156   if (!strcmp(c,"private")) {
157     public_ = 0;
158   } else if (!strcmp(c,"protected")) {
159     public_ = 2;
160   } else if (!strcmp(c,"C")) {
161     cdecl_ = 1;
162   } else if (!strcmp(c,"return_type")) {
163     storestring(read_word(),return_type);
164   } else {
165     Fl_Type::read_property(c);
166   }
167 }
168 
169 #include "function_panel.h"
170 #include <FL/fl_ask.H>
171 
open()172 void Fl_Function_Type::open() {
173   if (!function_panel) make_function_panel();
174   f_return_type_input->static_value(return_type);
175   f_name_input->static_value(name());
176   if (is_in_class()) {
177     f_public_member_choice->value(public_);
178     f_public_member_choice->show();
179     f_public_choice->hide();
180   } else {
181     f_public_choice->value(public_>0);
182     f_public_choice->show();
183     f_public_member_choice->hide();
184   }
185   f_c_button->value(cdecl_);
186   const char *c = comment();
187   f_comment_input->buffer()->text(c?c:"");
188   function_panel->show();
189   const char* message = 0;
190   for (;;) { // repeat as long as there are errors
191     if (message) fl_alert("%s", message);
192     for (;;) {
193       Fl_Widget* w = Fl::readqueue();
194       if (w == f_panel_cancel) goto BREAK2;
195       else if (w == f_panel_ok) break;
196       else if (!w) Fl::wait();
197     }
198     const char*c = f_name_input->value();
199     while (isspace(*c)) c++;
200     message = c_check(c); if (message) continue;
201     const char *d = c;
202     for (; *d != '('; d++) if (isspace(*d) || !*d) break;
203     if (*c && *d != '(') {
204       message = "must be name(arguments), try again:"; continue;
205     }
206     int mod = 0;
207     c = f_return_type_input->value();
208     message = c_check(c); if (message) continue;
209     name(f_name_input->value());
210     storestring(c, return_type);
211     if (is_in_class()) {
212       if (public_ != f_public_member_choice->value()) {
213         mod = 1;
214         public_ = f_public_member_choice->value();
215         redraw_browser();
216       }
217     } else {
218       if (public_ != f_public_choice->value()) {
219         mod = 1;
220         public_ = f_public_choice->value();
221         redraw_browser();
222       }
223     }
224     if (cdecl_ != f_c_button->value()) {
225       mod = 1;
226       cdecl_ = f_c_button->value();
227     }
228     c = f_comment_input->buffer()->text();
229     if (c && *c) {
230       if (!comment() || strcmp(c, comment())) redraw_browser();
231       comment(c);
232     } else {
233       if (comment()) redraw_browser();
234       comment(0);
235     }
236     if (c) free((void*)c);
237     if (mod) set_modflag(1);
238     break;
239   }
240 BREAK2:
241   function_panel->hide();
242 }
243 
244 Fl_Function_Type Fl_Function_type;
245 
246 extern const char* subclassname(Fl_Type*);
247 
write_code1()248 void Fl_Function_Type::write_code1() {
249   constructor=0;
250   havewidgets = 0;
251   Fl_Type *child;
252   // if the function has no children (hence no body), Fluid will not generate
253   // the function either. This is great if you decide to implement that function
254   // inside another module
255   char havechildren = 0;
256   for (child = next; child && child->level > level; child = child->next) {
257     havechildren = 1;
258     if (child->is_widget()) {
259       havewidgets = 1;
260       break;
261     }
262   }
263   if (havechildren)
264     write_c("\n");
265   if (ismain()) {
266     if (havechildren)
267       write_c("int main(int argc, char **argv) {\n");
268   } else {
269     const char* rtype = return_type;
270     const char* star = "";
271     // from matt: let the user type "static " at the start of type
272     // in order to declare a static method;
273     int is_static = 0;
274     int is_virtual = 0;
275     if (rtype) {
276       if (!strcmp(rtype,"static")) {is_static = 1; rtype = 0;}
277       else if (!strncmp(rtype, "static ",7)) {is_static = 1; rtype += 7;}
278       if (!strcmp(rtype, "virtual")) {is_virtual = 1; rtype = 0;}
279       else if (!strncmp(rtype, "virtual ",8)) {is_virtual = 1; rtype += 8;}
280     }
281     if (!rtype) {
282       if (havewidgets) {
283         rtype = subclassname(child);
284         star = "*";
285       } else rtype = "void";
286     }
287 
288     const char* k = class_name(0);
289     if (k) {
290       if (havechildren)
291         write_comment_c();
292       write_public(public_);
293       if (name()[0] == '~')
294         constructor = 1;
295       else {
296         size_t n = strlen(k);
297         if (!strncmp(name(), k, n) && name()[n] == '(') constructor = 1;
298       }
299       write_h("  ");
300       if (is_static) write_h("static ");
301       if (is_virtual) write_h("virtual ");
302       if (!constructor) {
303         write_h("%s%s ", rtype, star);
304         if (havechildren)
305           write_c("%s%s ", rtype, star);
306       }
307 
308       // if this is a subclass, only write_h() the part before the ':'
309       char s[1024], *sptr = s;
310       char *nptr = (char *)name();
311 
312       while (*nptr) {
313         if (*nptr == ':') {
314           if (nptr[1] != ':') break;
315           // Copy extra ":" for "class::member"...
316           *sptr++ = *nptr++;
317         }
318         *sptr++ = *nptr++;
319       }
320       *sptr = '\0';
321 
322       write_h("%s;\n", s);
323       // skip all function default param. init in body:
324       int skips=0,skipc=0;
325       int nc=0,plevel=0;
326       for (sptr=s,nptr=(char*)name(); *nptr; nc++,nptr++) {
327         if (!skips && *nptr=='(') plevel++;
328         else if (!skips && *nptr==')') plevel--;
329         if ( *nptr=='"' &&  !(nc &&  *(nptr-1)=='\\') )
330           skips = skips ? 0 : 1;
331         else if(!skips && *nptr=='\'' &&  !(nc &&  *(nptr-1)=='\\'))
332           skipc = skipc ? 0 : 1;
333         if(!skips && !skipc && plevel==1 && *nptr =='=' &&
334            !(nc && *(nptr-1)=='\'') ) // ignore '=' case
335           while(*++nptr  && (skips || skipc || ( (*nptr!=',' && *nptr!=')') || plevel!=1) )) {
336             if ( *nptr=='"' &&  *(nptr-1)!='\\' )
337               skips = skips ? 0 : 1;
338             else if(!skips && *nptr=='\'' &&  *(nptr-1)!='\\')
339               skipc = skipc ? 0 : 1;
340             if (!skips && !skipc && *nptr=='(') plevel++;
341             else if (!skips && *nptr==')') plevel--;
342           }
343 
344         if (sptr < (s + sizeof(s) - 1))	*sptr++ = *nptr;
345       }
346       *sptr = '\0';
347 
348       if (havechildren)
349         write_c("%s::%s {\n", k, s);
350     } else {
351       if (havechildren)
352         write_comment_c();
353       if (public_) {
354         if (cdecl_)
355           write_h("extern \"C\" { %s%s %s; }\n", rtype, star, name());
356         else
357           write_h("%s%s %s;\n", rtype, star, name());
358       } else {
359         if (havechildren)
360           write_c("static ");
361       }
362 
363       // write everything but the default parameters (if any)
364       char s[1024], *sptr;
365       char *nptr;
366       int skips=0,skipc=0;
367       int nc=0,plevel=0;
368       for (sptr=s,nptr=(char*)name(); *nptr; nc++,nptr++) {
369         if (!skips && *nptr=='(') plevel++;
370         else if (!skips && *nptr==')') plevel--;
371         if ( *nptr=='"' &&  !(nc &&  *(nptr-1)=='\\') )
372           skips = skips ? 0 : 1;
373         else if(!skips && *nptr=='\'' &&  !(nc &&  *(nptr-1)=='\\'))
374           skipc = skipc ? 0 : 1;
375         if(!skips && !skipc && plevel==1 && *nptr =='=' &&
376            !(nc && *(nptr-1)=='\'') ) // ignore '=' case
377           while(*++nptr  && (skips || skipc || ( (*nptr!=',' && *nptr!=')') || plevel!=1) )) {
378             if ( *nptr=='"' &&  *(nptr-1)!='\\' )
379               skips = skips ? 0 : 1;
380             else if(!skips && *nptr=='\'' &&  *(nptr-1)!='\\')
381               skipc = skipc ? 0 : 1;
382             if (!skips && !skipc && *nptr=='(') plevel++;
383             else if (!skips && *nptr==')') plevel--;
384           }
385 
386         if (sptr < (s + sizeof(s) - 1))	*sptr++ = *nptr;
387       }
388       *sptr = '\0';
389 
390       if (havechildren)
391         write_c("%s%s %s {\n", rtype, star, s);
392     }
393   }
394 
395   if (havewidgets && !child->name()) write_c("  %s* w;\n", subclassname(child));
396   indentation += 2;
397 }
398 
write_code2()399 void Fl_Function_Type::write_code2() {
400   Fl_Type *child;
401   const char *var = "w";
402   char havechildren = 0;
403   for (child = next; child && child->level > level; child = child->next) {
404     havechildren = 1;
405     if (child->is_window() && child->name()) var = child->name();
406   }
407 
408   if (ismain()) {
409     if (havewidgets) write_c("  %s->show(argc, argv);\n", var);
410     if (havechildren) write_c("  return Fl::run();\n");
411   } else if (havewidgets && !constructor && !return_type) {
412     write_c("  return %s;\n", var);
413   }
414   if (havechildren)
415     write_c("}\n");
416   indentation = 0;
417 }
418 
has_signature(const char * rtype,const char * sig) const419 int Fl_Function_Type::has_signature(const char *rtype, const char *sig) const {
420   if (rtype && !return_type) return 0;
421   if (!name()) return 0;
422   if ( (rtype==0L || strcmp(return_type, rtype)==0)
423       && fl_filename_match(name(), sig)) {
424     return 1;
425   }
426   return 0;
427 }
428 
429 ////////////////////////////////////////////////////////////////
430 
make()431 Fl_Type *Fl_Code_Type::make() {
432   Fl_Type *p = Fl_Type::current;
433   while (p && !p->is_code_block()) p = p->parent;
434   if (!p) {
435     fl_message("Please select a function");
436     return 0;
437   }
438   Fl_Code_Type *o = new Fl_Code_Type();
439   o->name("printf(\"Hello, World!\\n\");");
440   o->add(p);
441   o->factory = this;
442   return o;
443 }
444 
open()445 void Fl_Code_Type::open() {
446   if (!code_panel) make_code_panel();
447   const char *text = name();
448   code_input->buffer()->text( text ? text : "" );
449   code_panel->show();
450   const char* message = 0;
451   for (;;) { // repeat as long as there are errors
452     if (message) fl_alert("%s", message);
453     for (;;) {
454       Fl_Widget* w = Fl::readqueue();
455       if (w == code_panel_cancel) goto BREAK2;
456       else if (w == code_panel_ok) break;
457       else if (!w) Fl::wait();
458     }
459     char*c = code_input->buffer()->text();
460     message = c_check(c); if (message) continue;
461     name(c);
462     free(c);
463     break;
464   }
465 BREAK2:
466   code_panel->hide();
467 }
468 
469 Fl_Code_Type Fl_Code_type;
470 
write_code1()471 void Fl_Code_Type::write_code1() {
472   const char* c = name();
473   if (!c) return;
474   const char *pch;
475   const char *ind = indent();
476   while( (pch=strchr(c,'\n')) )
477   {
478     int line_len = pch - c;
479     write_c("%s%.*s\n", ind, line_len, c);
480     c = pch+1;
481   }
482   write_c("%s%s\n", ind, c);
483 }
484 
write_code2()485 void Fl_Code_Type::write_code2() {}
486 
487 ////////////////////////////////////////////////////////////////
488 
make()489 Fl_Type *Fl_CodeBlock_Type::make() {
490   Fl_Type *p = Fl_Type::current;
491   while (p && !p->is_code_block()) p = p->parent;
492   if (!p) {
493     fl_message("Please select a function");
494     return 0;
495   }
496   Fl_CodeBlock_Type *o = new Fl_CodeBlock_Type();
497   o->name("if (test())");
498   o->after = 0;
499   o->add(p);
500   o->factory = this;
501   return o;
502 }
503 
write_properties()504 void Fl_CodeBlock_Type::write_properties() {
505   Fl_Type::write_properties();
506   if (after) {
507     write_string("after");
508     write_word(after);
509   }
510 }
511 
read_property(const char * c)512 void Fl_CodeBlock_Type::read_property(const char *c) {
513   if (!strcmp(c,"after")) {
514     storestring(read_word(),after);
515   } else {
516     Fl_Type::read_property(c);
517   }
518 }
519 
open()520 void Fl_CodeBlock_Type::open() {
521   if (!codeblock_panel) make_codeblock_panel();
522   code_before_input->static_value(name());
523   code_after_input->static_value(after);
524   codeblock_panel->show();
525   const char* message = 0;
526   for (;;) { // repeat as long as there are errors
527     if (message) fl_alert("%s", message);
528     for (;;) {
529       Fl_Widget* w = Fl::readqueue();
530       if (w == codeblock_panel_cancel) goto BREAK2;
531       else if (w == codeblock_panel_ok) break;
532       else if (!w) Fl::wait();
533     }
534     const char*c = code_before_input->value();
535     message = c_check(c); if (message) continue;
536     name(c);
537     c = code_after_input->value();
538     message = c_check(c); if (message) continue;
539     storestring(c, after);
540     break;
541   }
542 BREAK2:
543   codeblock_panel->hide();
544 }
545 
546 Fl_CodeBlock_Type Fl_CodeBlock_type;
547 
write_code1()548 void Fl_CodeBlock_Type::write_code1() {
549   const char* c = name();
550   write_c("%s%s {\n", indent(), c ? c : "");
551   indentation += 2;
552 }
553 
write_code2()554 void Fl_CodeBlock_Type::write_code2() {
555   indentation -= 2;
556   if (after) write_c("%s} %s\n", indent(), after);
557   else write_c("%s}\n", indent());
558 }
559 
560 ////////////////////////////////////////////////////////////////
561 
is_public() const562 int Fl_Decl_Type::is_public() const
563 {
564   Fl_Type *p = parent;
565   while (p && !p->is_decl_block()) p = p->parent;
566   if(p && p->is_public() && public_)
567     return public_;
568   else if(!p)
569     return public_;
570   return 0;
571 }
572 
make()573 Fl_Type *Fl_Decl_Type::make() {
574   Fl_Type *p = Fl_Type::current;
575   while (p && !p->is_decl_block()) p = p->parent;
576   Fl_Decl_Type *o = new Fl_Decl_Type();
577   o->public_ = 0;
578   o->static_ = 1;
579   o->name("int x;");
580   o->add(p);
581   o->factory = this;
582   return o;
583 }
584 
write_properties()585 void Fl_Decl_Type::write_properties() {
586   Fl_Type::write_properties();
587   switch (public_) {
588     case 0: write_string("private"); break;
589     case 1: write_string("public"); break;
590     case 2: write_string("protected"); break;
591   }
592   if (static_)
593     write_string("local");
594   else
595     write_string("global");
596 }
597 
read_property(const char * c)598 void Fl_Decl_Type::read_property(const char *c) {
599   if (!strcmp(c,"public")) {
600     public_ = 1;
601   } else if (!strcmp(c,"private")) {
602     public_ = 0;
603   } else if (!strcmp(c,"protected")) {
604     public_ = 2;
605   } else if (!strcmp(c,"local")) {
606     static_ = 1;
607   } else if (!strcmp(c,"global")) {
608     static_ = 0;
609   } else {
610     Fl_Type::read_property(c);
611   }
612 }
613 
open()614 void Fl_Decl_Type::open() {
615   if (!decl_panel) make_decl_panel();
616   decl_input->static_value(name());
617   if (is_in_class()) {
618     decl_class_choice->value(public_);
619     decl_class_choice->show();
620     decl_choice->hide();
621   } else {
622     decl_choice->value((public_&1)|((static_&1)<<1));
623     decl_choice->show();
624     decl_class_choice->hide();
625   }
626   const char *c = comment();
627   decl_comment_input->buffer()->text(c?c:"");
628   decl_panel->show();
629   const char* message = 0;
630   for (;;) { // repeat as long as there are errors
631     if (message) fl_alert("%s", message);
632     for (;;) {
633       Fl_Widget* w = Fl::readqueue();
634       if (w == decl_panel_cancel) goto BREAK2;
635       else if (w == decl_panel_ok) break;
636       else if (!w) Fl::wait();
637     }
638     const char*c = decl_input->value();
639     while (isspace(*c)) c++;
640     message = c_check(c&&c[0]=='#' ? c+1 : c);
641     if (message) continue;
642     name(c);
643     if (is_in_class()) {
644       if (public_!=decl_class_choice->value()) {
645         set_modflag(1);
646         public_ = decl_class_choice->value();
647       }
648     } else {
649       if (public_!=(decl_choice->value()&1)) {
650         set_modflag(1);
651         public_ = (decl_choice->value()&1);
652       }
653       if (static_!=((decl_choice->value()>>1)&1)) {
654         set_modflag(1);
655         static_ = ((decl_choice->value()>>1)&1);
656       }
657     }
658     c = decl_comment_input->buffer()->text();
659     if (c && *c) {
660       if (!comment() || strcmp(c, comment())) redraw_browser();
661       comment(c);
662     } else {
663       if (comment()) redraw_browser();
664       comment(0);
665     }
666     if (c) free((void*)c);
667     break;
668   }
669 BREAK2:
670   decl_panel->hide();
671 }
672 
673 Fl_Decl_Type Fl_Decl_type;
674 
write_code1()675 void Fl_Decl_Type::write_code1() {
676   const char* c = name();
677   if (!c) return;
678   // handle a few keywords differently if inside a class
679   if (is_in_class() && (   (!strncmp(c,"class",5) && isspace(c[5]))
680                         || (!strncmp(c,"typedef",7) && isspace(c[7]))
681                         || (!strncmp(c,"FL_EXPORT",9) && isspace(c[9]))
682                         || (!strncmp(c,"struct",6) && isspace(c[6]))
683                         ) ) {
684     write_public(public_);
685     write_comment_h("  ");
686     write_h("  %s\n", c);
687     return;
688   }
689   // handle putting #include, extern, using or typedef into decl:
690   if (   (!isalpha(*c) && *c != '~')
691       || (!strncmp(c,"extern",6) && isspace(c[6]))
692       || (!strncmp(c,"class",5) && isspace(c[5]))
693       || (!strncmp(c,"typedef",7) && isspace(c[7]))
694       || (!strncmp(c,"using",5) && isspace(c[5]))
695       || (!strncmp(c,"FL_EXPORT",9) && isspace(c[9]))
696       //    || !strncmp(c,"struct",6) && isspace(c[6])
697       ) {
698     if (public_) {
699       write_comment_h();
700       write_h("%s\n", c);
701     } else {
702       write_comment_c();
703       write_c("%s\n", c);
704     }
705     return;
706   }
707   // find the first C++ style comment
708   const char* e = c+strlen(c), *csc = c;
709   while (csc<e && (csc[0]!='/' || csc[1]!='/')) csc++;
710   if (csc!=e) e = csc; // comment found
711                        // lose all trailing semicolons so I can add one:
712   while (e>c && e[-1]==' ') e--;
713   while (e>c && e[-1]==';') e--;
714   if (class_name(1)) {
715     write_public(public_);
716     write_comment_h("  ");
717     write_h("  %.*s; %s\n", (int)(e-c), c, csc);
718   } else {
719     if (public_) {
720       if (static_)
721         write_h("extern ");
722       else
723         write_comment_h();
724       write_h("%.*s; %s\n", (int)(e-c), c, csc);
725       if (static_) {
726         write_comment_c();
727         write_c("%.*s; %s\n", (int)(e-c), c, csc);
728       }
729     } else {
730       write_comment_c();
731       if (static_)
732         write_c("static ");
733       write_c("%.*s; %s\n", (int)(e-c), c, csc);
734     }
735   }
736 }
737 
write_code2()738 void Fl_Decl_Type::write_code2() {}
739 
740 ////////////////////////////////////////////////////////////////
741 
make()742 Fl_Type *Fl_Data_Type::make() {
743   Fl_Type *p = Fl_Type::current;
744   while (p && !p->is_decl_block()) p = p->parent;
745   Fl_Data_Type *o = new Fl_Data_Type();
746   o->public_ = 1;
747   o->static_ = 1;
748   o->filename_ = 0;
749   o->name("myBinaryData");
750   o->add(p);
751   o->factory = this;
752   return o;
753 }
754 
write_properties()755 void Fl_Data_Type::write_properties() {
756   Fl_Decl_Type::write_properties();
757   if (filename_) {
758     write_string("filename");
759     write_word(filename_);
760   }
761 }
762 
read_property(const char * c)763 void Fl_Data_Type::read_property(const char *c) {
764   if (!strcmp(c,"filename")) {
765     storestring(read_word(), filename_, 1);
766   } else {
767     Fl_Decl_Type::read_property(c);
768   }
769 }
770 
open()771 void Fl_Data_Type::open() {
772   if (!data_panel) make_data_panel();
773   data_input->static_value(name());
774   if (is_in_class()) {
775     data_class_choice->value(public_);
776     data_class_choice->show();
777     data_choice->hide();
778   } else {
779     data_choice->value((public_&1)|((static_&1)<<1));
780     data_choice->show();
781     data_class_choice->hide();
782   }
783   data_filename->value(filename_?filename_:"");
784   const char *c = comment();
785   data_comment_input->buffer()->text(c?c:"");
786   data_panel->show();
787   const char* message = 0;
788   for (;;) { // repeat as long as there are errors
789     if (message) fl_alert("%s", message);
790     for (;;) {
791       Fl_Widget* w = Fl::readqueue();
792       if (w == data_panel_cancel) goto BREAK2;
793       else if (w == data_panel_ok) break;
794       else if (w == data_filebrowser) {
795         goto_source_dir();
796         const char *fn = fl_file_chooser("Load Binary Data", 0L, data_filename->value(), 1);
797         leave_source_dir();
798         if (fn) {
799           if (strcmp(fn, data_filename->value()))
800             set_modflag(1);
801           data_filename->value(fn);
802         }
803       }
804       else if (!w) Fl::wait();
805     }
806     // store the variable name:
807     const char*c = data_input->value();
808     char *s = strdup(c), *p = s, *q, *n;
809     for (;;++p) {
810       if (!isspace((unsigned char)(*p))) break;
811     }
812     n = p;
813     if ( (!isalpha((unsigned char)(*p))) && ((*p)!='_') && ((*p)!=':') ) goto OOPS;
814     ++p;
815     for (;;++p) {
816       if ( (!isalnum((unsigned char)(*p))) && ((*p)!='_') && ((*p)!=':') ) break;
817     }
818     q = p;
819     for (;;++q) {
820       if (!*q) break;
821       if (!isspace((unsigned char)(*q))) goto OOPS;
822     }
823     if (n==q) {
824     OOPS: message = "variable name must be a C identifier";
825       free((void*)s);
826       continue;
827     }
828     *p = 0;
829     name(n);
830     free(s);
831     // store flags
832     if (is_in_class()) {
833       if (public_!=data_class_choice->value()) {
834         set_modflag(1);
835         public_ = data_class_choice->value();
836       }
837     } else {
838       if (public_!=(data_choice->value()&1)) {
839         set_modflag(1);
840         public_ = (data_choice->value()&1);
841       }
842       if (static_!=((data_choice->value()>>1)&1)) {
843         set_modflag(1);
844         static_ = ((data_choice->value()>>1)&1);
845       }
846     }
847     // store the filename
848     c = data_filename->value();
849     if (filename_ && strcmp(filename_, data_filename->value()))
850       set_modflag(1);
851     else if (!filename_ && *c)
852       set_modflag(1);
853     if (filename_) { free((void*)filename_); filename_ = 0L; }
854     if (c && *c) filename_ = strdup(c);
855     // store the comment
856     c = data_comment_input->buffer()->text();
857     if (c && *c) {
858       if (!comment() || strcmp(c, comment())) redraw_browser();
859       comment(c);
860     } else {
861       if (comment()) redraw_browser();
862       comment(0);
863     }
864     if (c) free((void*)c);
865     break;
866   }
867 BREAK2:
868   data_panel->hide();
869 }
870 
871 Fl_Data_Type Fl_Data_type;
872 
write_code1()873 void Fl_Data_Type::write_code1() {
874   const char *message = 0;
875   const char *c = name();
876   if (!c) return;
877   const char *fn = filename_;
878   char *data = 0;
879   int nData = -1;
880   // path should be set correctly already
881   if (filename_ && !write_sourceview) {
882     FILE *f = fl_fopen(filename_, "rb");
883     if (!f) {
884       message = "Can't include binary file. Can't open";
885     } else {
886       fseek(f, 0, SEEK_END);
887       nData = ftell(f);
888       fseek(f, 0, SEEK_SET);
889       if (nData) {
890         data = (char*)calloc(nData, 1);
891         if (fread(data, nData, 1, f)==0) { /* use default */ }
892       }
893       fclose(f);
894     }
895   } else {
896     fn = "<no filename>";
897   }
898   if (is_in_class()) {
899     write_public(public_);
900     write_comment_h("  ");
901     write_h("  static unsigned char %s[%d];\n", c, nData);
902     write_c("unsigned char %s::%s[%d] = /* binary data included from %s */\n", class_name(1), c, nData, fn);
903     if (message) write_c("#error %s %s\n", message, fn);
904     write_cdata(data, nData);
905     write_c(";\n");
906   } else {
907     // the "header only" option does not apply here!
908     if (public_) {
909       if (static_) {
910         write_h("extern unsigned char %s[%d];\n", c, nData);
911         write_comment_c();
912         write_c("unsigned char %s[%d] = /* binary data included from %s */\n", c, nData, fn);
913         if (message) write_c("#error %s %s\n", message, fn);
914         write_cdata(data, nData);
915         write_c(";\n");
916       } else {
917         write_comment_h();
918         write_h("#error Unsupported declaration loading binary data %s\n", fn);
919         write_h("unsigned char %s[3] = { 1, 2, 3 };\n", c);
920       }
921     } else {
922       write_comment_c();
923       if (static_)
924         write_c("static ");
925       write_c("unsigned char %s[%d] = /* binary data included from %s */\n", c, nData, fn);
926       if (message) write_c("#error %s %s\n", message, fn);
927       write_cdata(data, nData);
928       write_c(";\n");
929     }
930   }
931   // if we are in interactive mode, we pop up a warning dialog
932   // giving the error: (compile_only && !write_sourceview)
933   if (message && !write_sourceview) {
934     if (compile_only)
935       fprintf(stderr, "FLUID ERROR: %s %s\n", message, fn);
936     else
937       fl_alert("%s\n%s\n", message, fn);
938   }
939   if (data) free(data);
940 }
941 
write_code2()942 void Fl_Data_Type::write_code2() {}
943 
944 ////////////////////////////////////////////////////////////////
945 
is_public() const946 int Fl_DeclBlock_Type::is_public() const {return public_;}
947 
make()948 Fl_Type *Fl_DeclBlock_Type::make() {
949   Fl_Type *p = Fl_Type::current;
950   while (p && !p->is_decl_block()) p = p->parent;
951   Fl_DeclBlock_Type *o = new Fl_DeclBlock_Type();
952   o->name("#if 1");
953   o->public_ = 0;
954   o->after = strdup("#endif");
955   o->add(p);
956   o->factory = this;
957   return o;
958 }
959 
write_properties()960 void Fl_DeclBlock_Type::write_properties() {
961   Fl_Type::write_properties();
962   switch (public_) {
963     case 1: write_string("public"); break;
964     case 2: write_string("protected"); break;
965   }
966   write_string("after");
967   write_word(after);
968 }
969 
read_property(const char * c)970 void Fl_DeclBlock_Type::read_property(const char *c) {
971   if(!strcmp(c,"public")) {
972     public_ = 1;
973   } else if(!strcmp(c,"protected")) {
974     public_ = 2;
975   } else  if (!strcmp(c,"after")) {
976     storestring(read_word(),after);
977   } else {
978     Fl_Type::read_property(c);
979   }
980 }
981 
open()982 void Fl_DeclBlock_Type::open() {
983   if (!declblock_panel) make_declblock_panel();
984   decl_before_input->static_value(name());
985   declblock_public_choice->value((public_>0));
986   decl_after_input->static_value(after);
987   declblock_panel->show();
988   const char* message = 0;
989   for (;;) { // repeat as long as there are errors
990     if (message) fl_alert("%s", message);
991     for (;;) {
992       Fl_Widget* w = Fl::readqueue();
993       if (w == declblock_panel_cancel) goto BREAK2;
994       else if (w == declblock_panel_ok) break;
995       else if (!w) Fl::wait();
996     }
997     const char*c = decl_before_input->value();
998     while (isspace(*c)) c++;
999     message = c_check(c&&c[0]=='#' ? c+1 : c);
1000     if (message) continue;
1001     name(c);
1002     c = decl_after_input->value();
1003     while (isspace(*c)) c++;
1004     message = c_check(c&&c[0]=='#' ? c+1 : c);
1005     if (message) continue;
1006     storestring(c,after);
1007     if (public_ != declblock_public_choice->value()) {
1008       set_modflag(1);
1009       public_ = declblock_public_choice->value();
1010       redraw_browser();
1011     }
1012     break;
1013   }
1014 BREAK2:
1015   declblock_panel->hide();
1016 }
1017 
1018 Fl_DeclBlock_Type Fl_DeclBlock_type;
1019 
write_code1()1020 void Fl_DeclBlock_Type::write_code1() {
1021   const char* c = name();
1022   if (public_)
1023     write_h("%s\n", c);
1024   write_c("%s\n", c);
1025 }
1026 
write_code2()1027 void Fl_DeclBlock_Type::write_code2() {
1028   const char* c = after;
1029   if (public_)
1030     write_h("%s\n", c);
1031   write_c("%s\n", c);
1032 }
1033 
1034 ////////////////////////////////////////////////////////////////
1035 
make()1036 Fl_Type *Fl_Comment_Type::make() {
1037   Fl_Type *p = Fl_Type::current;
1038   while (p && !p->is_code_block()) p = p->parent;
1039   Fl_Comment_Type *o = new Fl_Comment_Type();
1040   o->in_c_ = 1;
1041   o->in_h_ = 1;
1042   o->style_ = 0;
1043   o->name("my comment");
1044   o->add(p);
1045   o->factory = this;
1046   o->title_buf[0] = 0;
1047   return o;
1048 }
1049 
write_properties()1050 void Fl_Comment_Type::write_properties() {
1051   Fl_Type::write_properties();
1052   if (in_c_) write_string("in_source"); else write_string("not_in_source");
1053   if (in_h_) write_string("in_header"); else write_string("not_in_header");
1054 }
1055 
read_property(const char * c)1056 void Fl_Comment_Type::read_property(const char *c) {
1057   if (!strcmp(c,"in_source")) {
1058     in_c_ = 1;
1059   } else if (!strcmp(c,"not_in_source")) {
1060     in_c_ = 0;
1061   } else if (!strcmp(c,"in_header")) {
1062     in_h_ = 1;
1063   } else if (!strcmp(c,"not_in_header")) {
1064     in_h_ = 0;
1065   } else {
1066     Fl_Type::read_property(c);
1067   }
1068 }
1069 
1070 #include "comments.h"
1071 
load_comments_preset(Fl_Preferences & menu)1072 static void load_comments_preset(Fl_Preferences &menu) {
1073   static const char * const predefined_comment[] = {
1074     "GNU Public License/GPL Header",  "GNU Public License/GPL Footer",
1075     "GNU Public License/LGPL Header", "GNU Public License/LGPL Footer",
1076     "FLTK/Header", "FLTK/Footer" };
1077   int i;
1078   menu.set("n", 6);
1079   Fl_Preferences db(Fl_Preferences::USER, "fltk.org", "fluid_comments");
1080   for (i=0; i<6; i++) {
1081     menu.set(Fl_Preferences::Name(i), predefined_comment[i]);
1082     db.set(predefined_comment[i], comment_text[i]);
1083   }
1084 }
1085 
open()1086 void Fl_Comment_Type::open() {
1087   if (!comment_panel) make_comment_panel();
1088   const char *text = name();
1089   {
1090     int i=0, n=0;
1091     Fl_Preferences menu(Fl_Preferences::USER, "fltk.org", "fluid_comments_menu");
1092     comment_predefined->clear();
1093     comment_predefined->add("_Edit/Add current comment...");
1094     comment_predefined->add("_Edit/Remove last selection...");
1095     menu.get("n", n, -1);
1096     if (n==-1) load_comments_preset(menu);
1097     menu.get("n", n, 0);
1098     for (i=0;i<n;i++) {
1099       char *text;
1100       menu.get(Fl_Preferences::Name(i), text, "");
1101       comment_predefined->add(text);
1102       free(text);
1103     }
1104   }
1105   comment_input->buffer()->text( text ? text : "" );
1106   comment_in_source->value(in_c_);
1107   comment_in_header->value(in_h_);
1108   comment_panel->show();
1109   const char* message = 0;
1110   char itempath[FL_PATH_MAX]; itempath[0] = 0;
1111   int last_selected_item = 0;
1112   for (;;) { // repeat as long as there are errors
1113     if (message) fl_alert("%s", message);
1114     for (;;) {
1115       Fl_Widget* w = Fl::readqueue();
1116       if (w == comment_panel_cancel) goto BREAK2;
1117       else if (w == comment_panel_ok) break;
1118       else if (w == comment_predefined) {
1119         if (comment_predefined->value()==1) {
1120           // add the current comment to the database
1121           const char *xname = fl_input(
1122                                        "Please enter a name to reference the current\ncomment in your database.\n\n"
1123                                        "Use forward slashes '/' to create submenus.",
1124                                        "My Comment");
1125           if (xname) {
1126             char *name = strdup(xname);
1127             for (char*s=name;*s;s++) if (*s==':') *s = ';';
1128             int n;
1129             Fl_Preferences db(Fl_Preferences::USER, "fltk.org", "fluid_comments");
1130             db.set(name, comment_input->buffer()->text());
1131             Fl_Preferences menu(Fl_Preferences::USER, "fltk.org", "fluid_comments_menu");
1132             menu.get("n", n, 0);
1133             menu.set(Fl_Preferences::Name(n), name);
1134             menu.set("n", ++n);
1135             comment_predefined->add(name);
1136             free(name);
1137           }
1138         } else if (comment_predefined->value()==2) {
1139           // remove the last selected comment from the database
1140           if (itempath[0]==0 || last_selected_item==0) {
1141             fl_message("Please select an entry form this menu first.");
1142           } else if (fl_choice("Are you sure that you want to delete the entry\n"
1143 	                       "\"%s\"\nfrom the database?", "Cancel", "Delete",
1144 			       NULL, itempath)) {
1145             Fl_Preferences db(Fl_Preferences::USER, "fltk.org", "fluid_comments");
1146             db.deleteEntry(itempath);
1147             comment_predefined->remove(last_selected_item);
1148             Fl_Preferences menu(Fl_Preferences::USER, "fltk.org", "fluid_comments_menu");
1149             int i, n;
1150             for (i=4, n=0; i<comment_predefined->size(); i++) {
1151               const Fl_Menu_Item *mi = comment_predefined->menu()+i;
1152               if (comment_predefined->item_pathname(itempath, 255, mi)==0) {
1153                 if (itempath[0]=='/') memmove(itempath, itempath+1, 255);
1154                 if (itempath[0]) menu.set(Fl_Preferences::Name(n++), itempath);
1155               }
1156             }
1157             menu.set("n", n);
1158           }
1159         } else {
1160           // load the selected comment from the database
1161           if (comment_predefined->item_pathname(itempath, 255)==0) {
1162             if (itempath[0]=='/') memmove(itempath, itempath+1, 255);
1163             Fl_Preferences db(Fl_Preferences::USER, "fltk.org", "fluid_comments");
1164             char *text;
1165             db.get(itempath, text, "(no text found in data base)");
1166             comment_input->buffer()->text(text);
1167             free(text);
1168             last_selected_item = comment_predefined->value();
1169           }
1170         }
1171       }
1172       else if (w == comment_load) {
1173         // load a comment from disk
1174 	fl_file_chooser_ok_label("Use File");
1175         const char *fname = fl_file_chooser("Pick a comment", 0L, 0L);
1176 	fl_file_chooser_ok_label(NULL);
1177         if (fname) {
1178           if (comment_input->buffer()->loadfile(fname)) {
1179             fl_alert("Error loading file\n%s", fname);
1180           }
1181         }
1182       }
1183       else if (!w) Fl::wait();
1184     }
1185     char*c = comment_input->buffer()->text();
1186     name(c);
1187     free(c);
1188     int mod = 0;
1189     if (in_c_ != comment_in_source->value()) {
1190       in_c_ = comment_in_source->value();
1191       mod = 1;
1192     }
1193     if (in_h_ != comment_in_header->value()) {
1194       in_h_ = comment_in_header->value();
1195       mod = 1;
1196     }
1197     if (mod) set_modflag(1);
1198     break;
1199   }
1200 BREAK2:
1201   title_buf[0] = 0;
1202   comment_panel->hide();
1203 }
1204 
title()1205 const char *Fl_Comment_Type::title() {
1206   const char* n = name();
1207   if (!n || !*n) return type_name();
1208   if (title_buf[0]==0) {
1209     const char *s = n;
1210     char *d = title_buf;
1211     int i = 50;
1212     while (--i > 0) {
1213       char n = *s++;
1214       if (n==0) break;
1215       if (n=='\r') { *d++ = '\\'; *d++ = 'r'; i--; }
1216       else if (n=='\n') { *d++ = '\\'; *d++ = 'n'; i--; }
1217       else if (n<32) { *d++ = '^'; *d++ = 'A'+n; i--; }
1218       else *d++ = n;
1219     }
1220     if (i<=0) { *d++ = '.'; *d++ = '.'; *d++ = '.'; }
1221     *d++ = 0;
1222   }
1223   return title_buf;
1224 }
1225 
1226 Fl_Comment_Type Fl_Comment_type;
1227 
write_code1()1228 void Fl_Comment_Type::write_code1() {
1229   const char* c = name();
1230   if (!c) return;
1231   if (!in_c_ && !in_h_) return;
1232   // find out if there is already a valid comment:
1233   const char *s = c;
1234   while (isspace(*s)) s++;
1235   // if this seems to be a C style comment, copy the block as is
1236   // (it's up to the user to correctly close the comment)
1237   if (s[0]=='/' && s[1]=='*') {
1238     if (in_h_) write_h("%s\n", c);
1239     if (in_c_) write_c("%s\n", c);
1240     return;
1241   }
1242   // copy the comment line by line, add the double slash if needed
1243   char *txt = strdup(c);
1244   char *b = txt, *e = txt;
1245   for (;;) {
1246     // find the end of the line and set it to NUL
1247     while (*e && *e!='\n') e++;
1248     char eol = *e;
1249     *e = 0;
1250     // check if there is a C++ style comment at the beginning of the line
1251     char *s = b;
1252     while (isspace(*s)) s++;
1253     if (s!=e && ( s[0]!='/' || s[1]!='/') ) {
1254       // if no comment marker was found, we add one ourselves
1255       if (in_h_) write_h("// ");
1256       if (in_c_) write_c("// ");
1257     }
1258     // now copy the rest of the line
1259     if (in_h_) write_h("%s\n", b);
1260     if (in_c_) write_c("%s\n", b);
1261     if (eol==0) break;
1262     *e++ = eol;
1263     b = e;
1264   }
1265 }
1266 
write_code2()1267 void Fl_Comment_Type::write_code2() {}
1268 
1269 ////////////////////////////////////////////////////////////////
1270 
class_name(const int need_nest) const1271 const char* Fl_Type::class_name(const int need_nest) const {
1272   Fl_Type* p = parent;
1273   while (p) {
1274     if (p->is_class()) {
1275       // see if we are nested in another class, we must fully-qualify name:
1276       // this is lame but works...
1277       const char* q = 0;
1278       if(need_nest) q=p->class_name(need_nest);
1279       if (q) {
1280 	static char s[256];
1281 	if (q != s) strlcpy(s, q, sizeof(s));
1282 	strlcat(s, "::", sizeof(s));
1283 	strlcat(s, p->name(), sizeof(s));
1284 	return s;
1285       }
1286       return p->name();
1287     }
1288     p = p->parent;
1289   }
1290   return 0;
1291 }
1292 
1293 /**
1294  * If this Type resides inside a class, this function returns the class type, or null.
1295  */
is_in_class() const1296 const Fl_Class_Type *Fl_Type::is_in_class() const {
1297   Fl_Type* p = parent;
1298   while (p) {
1299     if (p->is_class()) {
1300       return (Fl_Class_Type*)p;
1301     }
1302     p = p->parent;
1303   }
1304   return 0;
1305 }
1306 
is_public() const1307 int Fl_Class_Type::is_public() const {return public_;}
1308 
prefix(const char * p)1309 void Fl_Class_Type::prefix(const char*p) {
1310   free((void*) class_prefix);
1311   class_prefix=strdup(p ? p : "" );
1312 }
1313 
make()1314 Fl_Type *Fl_Class_Type::make() {
1315   Fl_Type *p = Fl_Type::current;
1316   while (p && !p->is_decl_block()) p = p->parent;
1317   Fl_Class_Type *o = new Fl_Class_Type();
1318   o->name("UserInterface");
1319   o->class_prefix=0;
1320   o->subclass_of = 0;
1321   o->public_ = 1;
1322   o->add(p);
1323   o->factory = this;
1324   return o;
1325 }
1326 
write_properties()1327 void Fl_Class_Type::write_properties() {
1328   Fl_Type::write_properties();
1329   if (subclass_of) {
1330     write_string(":");
1331     write_word(subclass_of);
1332   }
1333   switch (public_) {
1334     case 0: write_string("private"); break;
1335     case 2: write_string("protected"); break;
1336   }
1337 }
1338 
read_property(const char * c)1339 void Fl_Class_Type::read_property(const char *c) {
1340   if (!strcmp(c,"private")) {
1341     public_ = 0;
1342   } else if (!strcmp(c,"protected")) {
1343     public_ = 2;
1344   } else if (!strcmp(c,":")) {
1345     storestring(read_word(), subclass_of);
1346   } else {
1347     Fl_Type::read_property(c);
1348   }
1349 }
1350 
open()1351 void Fl_Class_Type::open() {
1352   if (!class_panel) make_class_panel();
1353   char fullname[FL_PATH_MAX]="";
1354   if (prefix() && strlen(prefix()))
1355     sprintf(fullname,"%s %s",prefix(),name());
1356   else
1357     strcpy(fullname, name());
1358   c_name_input->static_value(fullname);
1359   c_subclass_input->static_value(subclass_of);
1360   c_public_button->value(public_);
1361   const char *c = comment();
1362   c_comment_input->buffer()->text(c?c:"");
1363   class_panel->show();
1364   const char* message = 0;
1365 
1366   char *na=0,*pr=0,*p=0; // name and prefix substrings
1367 
1368   for (;;) { // repeat as long as there are errors
1369     if (message) fl_alert("%s", message);
1370     for (;;) {
1371       Fl_Widget* w = Fl::readqueue();
1372       if (w == c_panel_cancel) goto BREAK2;
1373       else if (w == c_panel_ok) break;
1374       else if (!w) Fl::wait();
1375     }
1376     const char*c = c_name_input->value();
1377     char *s = strdup(c);
1378     size_t len = strlen(s);
1379     if (!*s) goto OOPS;
1380     p = (char*) (s+len-1);
1381     while (p>=s && isspace(*p)) *(p--)='\0';
1382     if (p<s) goto OOPS;
1383     while (p>=s && is_id(*p)) p--;
1384     if ( (p<s && !is_id(*(p+1))) || !*(p+1) ) {
1385     OOPS: message = "class name must be C++ identifier";
1386       free((void*)s);
1387       continue;
1388     }
1389     na=p+1; // now we have the name
1390     if(p>s) *p--='\0';
1391     while (p>=s && isspace(*p)) *(p--)='\0';
1392     while (p>=s && is_id(*p))   p--;
1393     if (p<s)                    p++;
1394     if (is_id(*p) && p<na)      pr=p; // prefix detected
1395     c = c_subclass_input->value();
1396     message = c_check(c);
1397     if (message) { free((void*)s);continue;}
1398     name(na);
1399     prefix(pr);
1400     free((void*)s);
1401     storestring(c, subclass_of);
1402     if (public_ != c_public_button->value()) {
1403       public_ = c_public_button->value();
1404       set_modflag(1);
1405     }
1406     c = c_comment_input->buffer()->text();
1407     if (c && *c) {
1408       if (!comment() || strcmp(c, comment())) redraw_browser();
1409       comment(c);
1410     } else {
1411       if (comment()) redraw_browser();
1412       comment(0);
1413     }
1414     if (c) free((void*)c);
1415     break;
1416   }
1417 BREAK2:
1418   class_panel->hide();
1419 }
1420 
1421 Fl_Class_Type Fl_Class_type;
1422 
1423 Fl_Class_Type *current_class;
1424 extern Fl_Widget_Class_Type *current_widget_class;
write_public(int state)1425 void write_public(int state) {
1426   if (!current_class && !current_widget_class) return;
1427   if (current_class && current_class->write_public_state == state) return;
1428   if (current_widget_class && current_widget_class->write_public_state == state) return;
1429   if (current_class) current_class->write_public_state = state;
1430   if (current_widget_class) current_widget_class->write_public_state = state;
1431   switch (state) {
1432     case 0: write_h("private:\n"); break;
1433     case 1: write_h("public:\n"); break;
1434     case 2: write_h("protected:\n"); break;
1435   }
1436 }
1437 
write_code1()1438 void Fl_Class_Type::write_code1() {
1439   parent_class = current_class;
1440   current_class = this;
1441   write_public_state = 0;
1442   write_h("\n");
1443   write_comment_h();
1444   if (prefix() && strlen(prefix()))
1445     write_h("class %s %s ", prefix(), name());
1446   else
1447     write_h("class %s ", name());
1448   if (subclass_of) write_h(": %s ", subclass_of);
1449   write_h("{\n");
1450 }
1451 
write_code2()1452 void Fl_Class_Type::write_code2() {
1453   write_h("};\n");
1454   current_class = parent_class;
1455 }
1456 
1457 /**
1458  * Return 1 if this class contains a function with the given signature.
1459  */
has_function(const char * rtype,const char * sig) const1460 int Fl_Class_Type::has_function(const char *rtype, const char *sig) const {
1461   Fl_Type *child;
1462   for (child = next; child && child->level > level; child = child->next) {
1463     if (child->level == level+1 && strcmp(child->type_name(), "Function")==0) {
1464       const Fl_Function_Type *fn = (const Fl_Function_Type*)child;
1465       if (fn->has_signature(rtype, sig))
1466         return 1;
1467     }
1468   }
1469   return 0;
1470 }
1471 
1472 //
1473 // End of "$Id: Fl_Function_Type.cxx 8786 2011-06-07 11:41:36Z manolo $".
1474 //
1475