|
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) ![]() |
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 //