fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

code.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: code.cxx 7903 2010-11-28 21:06:39Z matt $"
00003 //
00004 // Code output routines for the Fast Light Tool Kit (FLTK).
00005 //
00006 // Copyright 1998-2010 by Bill Spitzak and others.
00007 //
00008 // This library is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU Library General Public
00010 // License as published by the Free Software Foundation; either
00011 // version 2 of the License, or (at your option) any later version.
00012 //
00013 // This library is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 // Library General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU Library General Public
00019 // License along with this library; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00021 // USA.
00022 //
00023 // Please report all bugs and problems on the following page:
00024 //
00025 //     http://www.fltk.org/str.php
00026 //
00027 
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include "../src/flstring.h"
00031 #include <stdarg.h>
00032 
00033 #include <FL/Fl.H>
00034 #include "Fl_Type.h"
00035 #include "alignment_panel.h"
00036 
00037 static FILE *code_file;
00038 static FILE *header_file;
00039 
00040 extern char i18n_program[];
00041 extern int i18n_type;
00042 extern const char* i18n_include;
00043 extern const char* i18n_function;
00044 extern const char* i18n_file;
00045 extern const char* i18n_set;
00046 
00047 // return true if c can be in a C identifier.  I needed this so
00048 // it is not messed up by locale settings:
00049 int is_id(char c) {
00050   return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_';
00051 }
00052 
00054 // Generate unique but human-readable identifiers:
00055 
00056 struct id {
00057   char* text;
00058   void* object;
00059   id *left, *right;
00060   id (const char* t, void* o) : text(strdup(t)), object(o) {left = right = 0;}
00061   ~id();
00062 };
00063 
00064 id::~id() {
00065   delete left;
00066   free((void *)text);
00067   delete right;
00068 }
00069 
00070 static id* id_root;
00071 
00072 const char* unique_id(void* o, const char* type, const char* name, const char* label) {
00073   char buffer[128];
00074   char* q = buffer;
00075   while (*type) *q++ = *type++;
00076   *q++ = '_';
00077   const char* n = name;
00078   if (!n || !*n) n = label;
00079   if (n && *n) {
00080     while (*n && !is_id(*n)) n++;
00081     while (is_id(*n)) *q++ = *n++;
00082   }
00083   *q = 0;
00084   // okay, search the tree and see if the name was already used:
00085   id** p = &id_root;
00086   int which = 0;
00087   while (*p) {
00088     int i = strcmp(buffer, (*p)->text);
00089     if (!i) {
00090       if ((*p)->object == o) return (*p)->text;
00091       // already used, we need to pick a new name:
00092       sprintf(q,"%x",++which);
00093       p = &id_root;
00094       continue;
00095     }
00096     else if (i < 0) p = &((*p)->left);
00097     else p  = &((*p)->right);
00098   }
00099   *p = new id(buffer, o);
00100   return (*p)->text;
00101 }
00102 
00104 // return current indentation:
00105 
00106 static const char* spaces = "                ";
00107 int indentation;
00108 const char* indent() {
00109   int i = indentation; if (i>16) i = 16;
00110   return spaces+16-i;
00111 }
00112 
00114 // declarations/include files:
00115 // Each string generated by write_declare is written only once to
00116 // the header file.  This is done by keeping a binary tree of all
00117 // the calls so far and not printing it if it is in the tree.
00118 
00119 struct included {
00120   char *text;
00121   included *left, *right;
00122   included(const char *t) {
00123     text = strdup(t);
00124     left = right = 0;
00125   }
00126   ~included();
00127 };
00128 
00129 included::~included() {
00130   delete left;
00131   free((void *)text);
00132   delete right;
00133 }
00134 static included *included_root;
00135 
00136 int write_declare(const char *format, ...) {
00137   va_list args;
00138   char buf[1024];
00139   va_start(args, format);
00140   vsnprintf(buf, sizeof(buf), format, args);
00141   va_end(args);
00142   included **p = &included_root;
00143   while (*p) {
00144     int i = strcmp(buf,(*p)->text);
00145     if (!i) return 0;
00146     else if (i < 0) p = &((*p)->left);
00147     else p  = &((*p)->right);
00148   }
00149   fprintf(header_file,"%s\n",buf);
00150   *p = new included(buf);
00151   return 1;
00152 }
00153 
00155 
00156 // silly thing to prevent declaring unused variables:
00157 // When this symbol is on, all attempts to write code don't write
00158 // anything, but set a variable if it looks like the variable "o" is used:
00159 int varused_test;
00160 int varused;
00161 
00162 // write an array of C characters (adds a null):
00163 void write_cstring(const char *w, int length) {
00164   if (varused_test) {
00165     varused = 1;
00166     return;
00167   }
00168   const char *e = w+length;
00169   int linelength = 1;
00170   putc('\"', code_file);
00171   for (; w < e;) {
00172     int c = *w++;
00173     switch (c) {
00174     case '\b': c = 'b'; goto QUOTED;
00175     case '\t': c = 't'; goto QUOTED;
00176     case '\n': c = 'n'; goto QUOTED;
00177     case '\f': c = 'f'; goto QUOTED;
00178     case '\r': c = 'r'; goto QUOTED;
00179     case '\"':
00180     case '\'':
00181     case '\\':
00182     QUOTED:
00183       if (linelength >= 77) {fputs("\\\n",code_file); linelength = 0;}
00184       putc('\\', code_file);
00185       putc(c, code_file);
00186       linelength += 2;
00187       break;
00188     case '?': // prevent trigraphs by writing ?? as ?\?
00189       if (*(w-2) == '?') goto QUOTED;
00190       // else fall through:
00191     default:
00192       if (c >= ' ' && c < 127) {
00193         // a legal ASCII character
00194         if (linelength >= 78) {fputs("\\\n",code_file); linelength = 0;}
00195         putc(c, code_file);
00196         linelength++;
00197         break;
00198       }
00199       // otherwise we must print it as an octal constant:
00200       c &= 255;
00201       if (c < 8) {
00202         if (linelength >= 76) {fputs("\\\n",code_file); linelength = 0;}
00203         fprintf(code_file, "\\%o",c);
00204         linelength += 2;
00205       } else if (c < 64) {
00206         if (linelength >= 75) {fputs("\\\n",code_file); linelength = 0;}
00207         fprintf(code_file, "\\%o",c);
00208         linelength += 3;
00209       } else {
00210         if (linelength >= 74) {fputs("\\\n",code_file); linelength = 0;}
00211         fprintf(code_file, "\\%o",c);
00212         linelength += 4;
00213       }
00214       // We must not put more numbers after it, because some C compilers
00215       // consume them as part of the quoted sequence.  Use string constant
00216       // pasting to avoid this:
00217       c = *w;
00218       if (w < e && ( (c>='0'&&c<='9') || (c>='a'&&c<='f') || (c>='A'&&c<='F') )) {
00219         putc('\"', code_file); linelength++;
00220         if (linelength >= 79) {fputs("\n",code_file); linelength = 0;}
00221         putc('\"', code_file); linelength++;
00222       }
00223       break;
00224     }
00225   }
00226   putc('\"', code_file);
00227 }
00228 
00229 // write a C string, quoting characters if necessary:
00230 void write_cstring(const char *w) {write_cstring(w,strlen(w));}
00231 
00232 // write an array of C binary data (does not add a null):
00233 void write_cdata(const char *s, int length) {
00234   if (varused_test) {
00235     varused = 1;
00236     return;
00237   }
00238   if (write_sourceview) {
00239     if (length>=0)
00240       fprintf(code_file, "{ /* ... %d bytes of binary data... */ }", length);
00241     else
00242       fprintf(code_file, "{ /* ... binary data... */ }");
00243     return;
00244   }
00245   if (length==-1) {
00246     fprintf(code_file, "{ /* ... undefined size binary data... */ }");
00247     return;
00248   }
00249   const unsigned char *w = (const unsigned char *)s;
00250   const unsigned char *e = w+length;
00251   int linelength = 1;
00252   putc('{', code_file);
00253   for (; w < e;) {
00254     unsigned char c = *w++;
00255     if (c>99) linelength += 4;
00256     else if (c>9) linelength += 3;
00257     else linelength += 2;
00258     if (linelength >= 77) {fputs("\n",code_file); linelength = 0;}
00259     fprintf(code_file, "%d", c);
00260     if (w<e) putc(',', code_file);
00261   }
00262   putc('}', code_file);
00263 }
00264 
00265 void write_c(const char* format,...) {
00266   if (varused_test) {
00267     varused = 1;
00268     return;
00269   }
00270   va_list args;
00271   va_start(args, format);
00272   vfprintf(code_file, format, args);
00273   va_end(args);
00274 }
00275 
00276 void write_h(const char* format,...) {
00277   if (varused_test) return;
00278   va_list args;
00279   va_start(args, format);
00280   vfprintf(header_file, format, args);
00281   va_end(args);
00282 }
00283 
00284 #include <FL/filename.H>
00285 int write_number;
00286 int write_sourceview;
00287 extern Fl_Widget_Class_Type *current_widget_class;
00288 
00289 // recursively dump code, putting children between the two parts
00290 // of the parent code:
00291 static Fl_Type* write_code(Fl_Type* p) {
00292   if (write_sourceview) {
00293     p->code_position = (int)ftell(code_file);
00294     if (p->header_position_end==-1)
00295       p->header_position = (int)ftell(header_file);
00296   }
00297   // write all code that come before the children code
00298   // (but don't write the last comment until the very end)
00299   if (!(p==Fl_Type::last && p->is_comment()))
00300     p->write_code1();
00301   // recursively write the code of all children
00302   Fl_Type* q;
00303   if (p->is_widget() && p->is_class()) {
00304     // Handle widget classes specially
00305     for (q = p->next; q && q->level > p->level;) {
00306       if (strcmp(q->type_name(), "Function")) q = write_code(q);
00307       else {
00308         int level = q->level;
00309         do {
00310           q = q->next;
00311         } while (q && q->level > level);
00312       }
00313     }
00314 
00315     // write all code that come after the children 
00316     p->write_code2();
00317 
00318     for (q = p->next; q && q->level > p->level;) {
00319       if (!strcmp(q->type_name(), "Function")) q = write_code(q);
00320       else {
00321         int level = q->level;
00322         do {
00323           q = q->next;
00324         } while (q && q->level > level);
00325       }
00326     }
00327 
00328     write_h("};\n");
00329     current_widget_class = 0L;
00330   } else {
00331     for (q = p->next; q && q->level > p->level;) q = write_code(q);
00332     // write all code that come after the children 
00333     p->write_code2();
00334   }
00335   if (write_sourceview) {
00336     p->code_position_end = (int)ftell(code_file);
00337     if (p->header_position_end==-1)
00338       p->header_position_end = (int)ftell(header_file);
00339   }
00340   return q;
00341 }
00342 
00343 extern const char* header_file_name;
00344 extern Fl_Class_Type *current_class;
00345 
00346 int write_code(const char *s, const char *t) {
00347   const char *filemode = "w";
00348   if (write_sourceview) 
00349     filemode = "wb";
00350   write_number++;
00351   delete id_root; id_root = 0;
00352   indentation = 0;
00353   current_class = 0L;
00354   current_widget_class = 0L;
00355   if (!s) code_file = stdout;
00356   else {
00357     FILE *f = fl_fopen(s, filemode);
00358     if (!f) return 0;
00359     code_file = f;
00360   }
00361   if (!t) header_file = stdout;
00362   else {
00363     FILE *f = fl_fopen(t, filemode);
00364     if (!f) {fclose(code_file); return 0;}
00365     header_file = f;
00366   }
00367   // if the first entry in the Type tree is a comment, then it is probably 
00368   // a copyright notice. We print that before anything else in the file!
00369   Fl_Type* first_type = Fl_Type::first;
00370   if (first_type && first_type->is_comment()) {
00371     if (write_sourceview) {
00372       first_type->code_position = (int)ftell(code_file);
00373       first_type->header_position = (int)ftell(header_file);
00374     }
00375     // it is ok to write non-recusive code here, because comments have no children or code2 blocks
00376     first_type->write_code1();
00377     if (write_sourceview) {
00378       first_type->code_position_end = (int)ftell(code_file);
00379       first_type->header_position_end = (int)ftell(header_file);
00380     }
00381     first_type = first_type->next;
00382   }
00383 
00384   const char *hdr = "\
00385 // generated by Fast Light User Interface Designer (fluid) version %.4f\n\n";
00386   fprintf(header_file, hdr, FL_VERSION);
00387   fprintf(code_file, hdr, FL_VERSION);
00388 
00389   {char define_name[102];
00390   const char* a = fl_filename_name(t);
00391   char* b = define_name;
00392   if (!isalpha(*a)) {*b++ = '_';}
00393   while (*a) {*b++ = isalnum(*a) ? *a : '_'; a++;}
00394   *b = 0;
00395   fprintf(header_file, "#ifndef %s\n", define_name);
00396   fprintf(header_file, "#define %s\n", define_name);
00397   }  
00398 
00399   write_declare("#include <FL/Fl.H>");
00400   if (i18n_type && i18n_include[0]) {
00401     if (i18n_include[0] != '<' &&
00402         i18n_include[0] != '\"')
00403       write_c("#include \"%s\"\n", i18n_include);
00404     else
00405       write_c("#include %s\n", i18n_include);
00406     if (i18n_type == 2) {
00407       if (i18n_file[0]) write_c("extern nl_catd %s;\n", i18n_file);
00408       else {
00409         write_c("// Initialize I18N stuff now for menus...\n");
00410         write_c("#include <locale.h>\n");
00411         write_c("static char *_locale = setlocale(LC_MESSAGES, \"\");\n");
00412         write_c("static nl_catd _catalog = catopen(\"%s\", 0);\n",
00413                    i18n_program);
00414       }
00415     }
00416   }
00417   if (t && include_H_from_C) {
00418     if (*header_file_name == '.' && strchr(header_file_name, '/') == NULL) {
00419       write_c("#include \"%s\"\n", fl_filename_name(t));
00420     } else {
00421       write_c("#include \"%s\"\n", t);
00422     }
00423   }
00424   for (Fl_Type* p = first_type; p;) {
00425     // write all static data for this & all children first
00426     if (write_sourceview) p->header_position = (int)ftell(header_file);
00427     p->write_static();
00428     if (write_sourceview) {
00429       p->header_position_end = (int)ftell(header_file);
00430       if (p->header_position==p->header_position_end) p->header_position_end = -1;
00431     }
00432     for (Fl_Type* q = p->next; q && q->level > p->level; q = q->next) {
00433       if (write_sourceview) q->header_position = (int)ftell(header_file);
00434       q->write_static();
00435       if (write_sourceview) {
00436         q->header_position_end = (int)ftell(header_file);
00437         if (q->header_position==q->header_position_end) q->header_position_end = -1;
00438       }
00439     }
00440     // then write the nested code:
00441     p = write_code(p);
00442   }
00443 
00444   delete included_root; included_root = 0;
00445 
00446   if (!s) return 1;
00447 
00448   fprintf(header_file, "#endif\n");
00449 
00450   Fl_Type* last_type = Fl_Type::last;
00451   if (last_type && last_type->is_comment()) {
00452     if (write_sourceview) {
00453       last_type->code_position = (int)ftell(code_file);
00454       last_type->header_position = (int)ftell(header_file);
00455     }
00456     last_type->write_code1();
00457     if (write_sourceview) {
00458       last_type->code_position_end = (int)ftell(code_file);
00459       last_type->header_position_end = (int)ftell(header_file);
00460     }
00461   }
00462 
00463   int x = fclose(code_file);
00464   code_file = 0;
00465   int y = fclose(header_file);
00466   header_file = 0;
00467   return x >= 0 && y >= 0;
00468 }
00469 
00470 int write_strings(const char *sfile) {
00471   FILE *fp = fl_fopen(sfile, "w");
00472   Fl_Type *p;
00473   Fl_Widget_Type *w;
00474   int i;
00475 
00476   if (!fp) return 1;
00477 
00478   switch (i18n_type) {
00479   case 0 : /* None, just put static text out */
00480       fprintf(fp, "# generated by Fast Light User Interface Designer (fluid) version %.4f\n",
00481               FL_VERSION);
00482       for (p = Fl_Type::first; p; p = p->next) {
00483         if (p->is_widget()) {
00484           w = (Fl_Widget_Type *)p;
00485 
00486           if (w->label()) {
00487             for (const char *s = w->label(); *s; s ++)
00488               if (*s < 32 || *s > 126 || *s == '\"')
00489                 fprintf(fp, "\\%03o", *s);
00490               else
00491                 putc(*s, fp);
00492             putc('\n', fp);
00493           }
00494 
00495           if (w->tooltip()) {
00496             for (const char *s = w->tooltip(); *s; s ++)
00497               if (*s < 32 || *s > 126 || *s == '\"')
00498                 fprintf(fp, "\\%03o", *s);
00499               else
00500                 putc(*s, fp);
00501             putc('\n', fp);
00502           }
00503         }
00504       }
00505       break;
00506   case 1 : /* GNU gettext, put a .po file out */
00507       fprintf(fp, "# generated by Fast Light User Interface Designer (fluid) version %.4f\n",
00508               FL_VERSION);
00509       for (p = Fl_Type::first; p; p = p->next) {
00510         if (p->is_widget()) {
00511           w = (Fl_Widget_Type *)p;
00512 
00513           if (w->label()) {
00514             const char *s;
00515 
00516             fputs("msgid \"", fp);
00517             for (s = w->label(); *s; s ++)
00518               if (*s < 32 || *s > 126 || *s == '\"')
00519                 fprintf(fp, "\\%03o", *s);
00520               else
00521                 putc(*s, fp);
00522             fputs("\"\n", fp);
00523 
00524             fputs("msgstr \"", fp);
00525             for (s = w->label(); *s; s ++)
00526               if (*s < 32 || *s > 126 || *s == '\"')
00527                 fprintf(fp, "\\%03o", *s);
00528               else
00529                 putc(*s, fp);
00530             fputs("\"\n", fp);
00531           }
00532 
00533           if (w->tooltip()) {
00534             const char *s;
00535 
00536             fputs("msgid \"", fp);
00537             for (s = w->tooltip(); *s; s ++)
00538               if (*s < 32 || *s > 126 || *s == '\"')
00539                 fprintf(fp, "\\%03o", *s);
00540               else
00541                 putc(*s, fp);
00542             fputs("\"\n", fp);
00543 
00544             fputs("msgstr \"", fp);
00545             for (s = w->tooltip(); *s; s ++)
00546               if (*s < 32 || *s > 126 || *s == '\"')
00547                 fprintf(fp, "\\%03o", *s);
00548               else
00549                 putc(*s, fp);
00550             fputs("\"\n", fp);
00551           }
00552         }
00553       }
00554       break;
00555   case 2 : /* POSIX catgets, put a .msg file out */
00556       fprintf(fp, "$ generated by Fast Light User Interface Designer (fluid) version %.4f\n",
00557               FL_VERSION);
00558       fprintf(fp, "$set %s\n", i18n_set);
00559       fputs("$quote \"\n", fp);
00560 
00561       for (i = 1, p = Fl_Type::first; p; p = p->next) {
00562         if (p->is_widget()) {
00563           w = (Fl_Widget_Type *)p;
00564 
00565           if (w->label()) {
00566             fprintf(fp, "%d \"", i ++);
00567             for (const char *s = w->label(); *s; s ++)
00568               if (*s < 32 || *s > 126 || *s == '\"')
00569                 fprintf(fp, "\\%03o", *s);
00570               else
00571                 putc(*s, fp);
00572             fputs("\"\n", fp);
00573           }
00574 
00575           if (w->tooltip()) {
00576             fprintf(fp, "%d \"", i ++);
00577             for (const char *s = w->tooltip(); *s; s ++)
00578               if (*s < 32 || *s > 126 || *s == '\"')
00579                 fprintf(fp, "\\%03o", *s);
00580               else
00581                 putc(*s, fp);
00582             fputs("\"\n", fp);
00583           }
00584         }
00585       }
00586       break;
00587   }
00588 
00589   return fclose(fp);
00590 }
00591 
00593 
00594 void Fl_Type::write_static() {}
00595 void Fl_Type::write_code1() {
00596   write_h("// Header for %s\n", title());
00597   write_c("// Code for %s\n", title());
00598 }
00599 void Fl_Type::write_code2() {}
00600 
00601 //
00602 // End of "$Id: code.cxx 7903 2010-11-28 21:06:39Z matt $".
00603 //