|
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: file.cxx 7903 2010-11-28 21:06:39Z matt $" 00003 // 00004 // Fluid file routines for the Fast Light Tool Kit (FLTK). 00005 // 00006 // You may find the basic read_* and write_* routines to 00007 // be useful for other programs. I have used them many times. 00008 // They are somewhat similar to tcl, using matching { and } 00009 // to quote strings. 00010 // 00011 // Copyright 1998-2010 by Bill Spitzak and others. 00012 // 00013 // This library is free software; you can redistribute it and/or 00014 // modify it under the terms of the GNU Library General Public 00015 // License as published by the Free Software Foundation; either 00016 // version 2 of the License, or (at your option) any later version. 00017 // 00018 // This library is distributed in the hope that it will be useful, 00019 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00020 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00021 // Library General Public License for more details. 00022 // 00023 // You should have received a copy of the GNU Library General Public 00024 // License along with this library; if not, write to the Free Software 00025 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00026 // USA. 00027 // 00028 // Please report all bugs and problems on the following page: 00029 // 00030 // http://www.fltk.org/str.php 00031 // 00032 00033 #include <stdio.h> 00034 #include <stdlib.h> 00035 #include "../src/flstring.h" 00036 #include <stdarg.h> 00037 #include "alignment_panel.h" 00038 00040 // BASIC FILE WRITING: 00041 00042 static FILE *fout; 00043 00044 int open_write(const char *s) { 00045 if (!s) {fout = stdout; return 1;} 00046 FILE *f = fl_fopen(s,"w"); 00047 if (!f) return 0; 00048 fout = f; 00049 return 1; 00050 } 00051 00052 int close_write() { 00053 if (fout != stdout) { 00054 int x = fclose(fout); 00055 fout = stdout; 00056 return x >= 0; 00057 } 00058 return 1; 00059 } 00060 00061 static int needspace; 00062 int is_id(char); // in code.C 00063 00064 // write a string, quoting characters if necessary: 00065 void write_word(const char *w) { 00066 if (needspace) putc(' ', fout); 00067 needspace = 1; 00068 if (!w || !*w) {fprintf(fout,"{}"); return;} 00069 const char *p; 00070 // see if it is a single word: 00071 for (p = w; is_id(*p); p++) ; 00072 if (!*p) {fprintf(fout,"%s",w); return;} 00073 // see if there are matching braces: 00074 int n = 0; 00075 for (p = w; *p; p++) { 00076 if (*p == '{') n++; 00077 else if (*p == '}') {n--; if (n<0) break;} 00078 } 00079 int mismatched = (n != 0); 00080 // write out brace-quoted string: 00081 putc('{', fout); 00082 for (; *w; w++) { 00083 switch (*w) { 00084 case '{': 00085 case '}': 00086 if (!mismatched) break; 00087 case '\\': 00088 case '#': 00089 putc('\\',fout); 00090 break; 00091 } 00092 putc(*w,fout); 00093 } 00094 putc('}', fout); 00095 } 00096 00097 // write an arbitrary formatted word, or a comment, etc: 00098 void write_string(const char *format, ...) { 00099 va_list args; 00100 va_start(args, format); 00101 if (needspace) fputc(' ',fout); 00102 vfprintf(fout, format, args); 00103 va_end(args); 00104 needspace = !isspace(format[strlen(format)-1] & 255); 00105 } 00106 00107 // start a new line and indent it for a given nesting level: 00108 void write_indent(int n) { 00109 fputc('\n',fout); 00110 while (n--) {fputc(' ',fout); fputc(' ',fout);} 00111 needspace = 0; 00112 } 00113 00114 // write a '{' at the given indenting level: 00115 void write_open(int) { 00116 if (needspace) fputc(' ',fout); 00117 fputc('{',fout); 00118 needspace = 0; 00119 } 00120 00121 // write a '}' at the given indenting level: 00122 void write_close(int n) { 00123 if (needspace) write_indent(n); 00124 fputc('}',fout); 00125 needspace = 1; 00126 } 00127 00129 // BASIC FILE READING: 00130 00131 static FILE *fin; 00132 static int lineno; 00133 static const char *fname; 00134 00135 int open_read(const char *s) { 00136 lineno = 1; 00137 if (!s) {fin = stdin; fname = "stdin"; return 1;} 00138 FILE *f = fl_fopen(s,"r"); 00139 if (!f) return 0; 00140 fin = f; 00141 fname = s; 00142 return 1; 00143 } 00144 00145 int close_read() { 00146 if (fin != stdin) { 00147 int x = fclose(fin); 00148 fin = 0; 00149 return x >= 0; 00150 } 00151 return 1; 00152 } 00153 00154 #include <FL/fl_message.H> 00155 00156 void read_error(const char *format, ...) { 00157 va_list args; 00158 va_start(args, format); 00159 if (!fin) { 00160 char buffer[1024]; 00161 vsnprintf(buffer, sizeof(buffer), format, args); 00162 fl_message("%s", buffer); 00163 } else { 00164 fprintf(stderr, "%s:%d: ", fname, lineno); 00165 vfprintf(stderr, format, args); 00166 fprintf(stderr, "\n"); 00167 } 00168 va_end(args); 00169 } 00170 00171 static int hexdigit(int x) { 00172 if (isdigit(x)) return x-'0'; 00173 if (isupper(x)) return x-'A'+10; 00174 if (islower(x)) return x-'a'+10; 00175 return 20; 00176 } 00177 00178 00179 static int read_quoted() { // read whatever character is after a \ . 00180 int c,d,x; 00181 switch(c = fgetc(fin)) { 00182 case '\n': lineno++; return -1; 00183 case 'a' : return('\a'); 00184 case 'b' : return('\b'); 00185 case 'f' : return('\f'); 00186 case 'n' : return('\n'); 00187 case 'r' : return('\r'); 00188 case 't' : return('\t'); 00189 case 'v' : return('\v'); 00190 case 'x' : /* read hex */ 00191 for (c=x=0; x<3; x++) { 00192 int ch = fgetc(fin); 00193 d = hexdigit(ch); 00194 if (d > 15) {ungetc(ch,fin); break;} 00195 c = (c<<4)+d; 00196 } 00197 break; 00198 default: /* read octal */ 00199 if (c<'0' || c>'7') break; 00200 c -= '0'; 00201 for (x=0; x<2; x++) { 00202 int ch = fgetc(fin); 00203 d = hexdigit(ch); 00204 if (d>7) {ungetc(ch,fin); break;} 00205 c = (c<<3)+d; 00206 } 00207 break; 00208 } 00209 return(c); 00210 } 00211 00212 // return a word read from the file, or NULL at the EOF: 00213 // This will skip all comments (# to end of line), and evaluate 00214 // all \xxx sequences and use \ at the end of line to remove the newline. 00215 // A word is any one of: 00216 // a continuous string of non-space chars except { and } and # 00217 // everything between matching {...} (unless wantbrace != 0) 00218 // the characters '{' and '}' 00219 00220 static char *buffer; 00221 static int buflen; 00222 static void expand_buffer(int length) { 00223 if (length >= buflen) { 00224 if (!buflen) { 00225 buflen = length+1; 00226 buffer = (char*)malloc(buflen); 00227 } else { 00228 buflen = 2*buflen; 00229 if (length >= buflen) buflen = length+1; 00230 buffer = (char *)realloc((void *)buffer,buflen); 00231 } 00232 } 00233 } 00234 00235 const char *read_word(int wantbrace) { 00236 int x; 00237 00238 // skip all the whitespace before it: 00239 for (;;) { 00240 x = getc(fin); 00241 if (x < 0 && feof(fin)) { // eof 00242 return 0; 00243 } else if (x == '#') { // comment 00244 do x = getc(fin); while (x >= 0 && x != '\n'); 00245 lineno++; 00246 continue; 00247 } else if (x == '\n') { 00248 lineno++; 00249 } else if (!isspace(x & 255)) { 00250 break; 00251 } 00252 } 00253 00254 expand_buffer(100); 00255 00256 if (x == '{' && !wantbrace) { 00257 00258 // read in whatever is between braces 00259 int length = 0; 00260 int nesting = 0; 00261 for (;;) { 00262 x = getc(fin); 00263 if (x<0) {read_error("Missing '}'"); break;} 00264 else if (x == '#') { // embedded comment 00265 do x = getc(fin); while (x >= 0 && x != '\n'); 00266 lineno++; 00267 continue; 00268 } else if (x == '\n') lineno++; 00269 else if (x == '\\') {x = read_quoted(); if (x<0) continue;} 00270 else if (x == '{') nesting++; 00271 else if (x == '}') {if (!nesting--) break;} 00272 buffer[length++] = x; 00273 expand_buffer(length); 00274 } 00275 buffer[length] = 0; 00276 return buffer; 00277 00278 } else if (x == '{' || x == '}') { 00279 // all the punctuation is a word: 00280 buffer[0] = x; 00281 buffer[1] = 0; 00282 return buffer; 00283 00284 } else { 00285 00286 // read in an unquoted word: 00287 int length = 0; 00288 for (;;) { 00289 if (x == '\\') {x = read_quoted(); if (x<0) continue;} 00290 else if (x<0 || isspace(x & 255) || x=='{' || x=='}' || x=='#') break; 00291 buffer[length++] = x; 00292 expand_buffer(length); 00293 x = getc(fin); 00294 } 00295 ungetc(x, fin); 00296 buffer[length] = 0; 00297 return buffer; 00298 00299 } 00300 } 00301 00303 00304 #include <FL/Fl.H> 00305 #include "Fl_Widget_Type.h" 00306 00307 // global int variables: 00308 extern int i18n_type; 00309 extern const char* i18n_include; 00310 extern const char* i18n_function; 00311 extern const char* i18n_file; 00312 extern const char* i18n_set; 00313 00314 00315 extern int header_file_set; 00316 extern int code_file_set; 00317 extern const char* header_file_name; 00318 extern const char* code_file_name; 00319 00320 int write_file(const char *filename, int selected_only) { 00321 if (!open_write(filename)) return 0; 00322 write_string("# data file for the Fltk User Interface Designer (fluid)\n" 00323 "version %.4f",FL_VERSION); 00324 if(!include_H_from_C) 00325 write_string("\ndo_not_include_H_from_C"); 00326 if(use_FL_COMMAND) 00327 write_string("\nuse_FL_COMMAND"); 00328 if (i18n_type) { 00329 write_string("\ni18n_type %d", i18n_type); 00330 write_string("\ni18n_include %s", i18n_include); 00331 switch (i18n_type) { 00332 case 1 : /* GNU gettext */ 00333 write_string("\ni18n_function %s", i18n_function); 00334 break; 00335 case 2 : /* POSIX catgets */ 00336 if (i18n_file[0]) write_string("\ni18n_file %s", i18n_file); 00337 write_string("\ni18n_set %s", i18n_set); 00338 break; 00339 } 00340 } 00341 if (!selected_only) { 00342 write_string("\nheader_name"); write_word(header_file_name); 00343 write_string("\ncode_name"); write_word(code_file_name); 00344 } 00345 for (Fl_Type *p = Fl_Type::first; p;) { 00346 if (!selected_only || p->selected) { 00347 p->write(); 00348 write_string("\n"); 00349 int q = p->level; 00350 for (p = p->next; p && p->level > q; p = p->next); 00351 } else { 00352 p = p->next; 00353 } 00354 } 00355 return close_write(); 00356 } 00357 00359 // read all the objects out of the input file: 00360 00361 void read_fdesign(); 00362 00363 double read_version; 00364 00365 extern Fl_Type *Fl_Type_make(const char *tn); 00366 00367 static void read_children(Fl_Type *p, int paste) { 00368 Fl_Type::current = p; 00369 for (;;) { 00370 const char *c = read_word(); 00371 REUSE_C: 00372 if (!c) { 00373 if (p && !paste) read_error("Missing '}'"); 00374 break; 00375 } 00376 00377 if (!strcmp(c,"}")) { 00378 if (!p) read_error("Unexpected '}'"); 00379 break; 00380 } 00381 00382 // this is the first word in a .fd file: 00383 if (!strcmp(c,"Magic:")) { 00384 read_fdesign(); 00385 return; 00386 } 00387 00388 if (!strcmp(c,"version")) { 00389 c = read_word(); 00390 read_version = strtod(c,0); 00391 if (read_version<=0 || read_version>FL_VERSION) 00392 read_error("unknown version '%s'",c); 00393 continue; 00394 } 00395 00396 // back compatibility with Vincent Penne's original class code: 00397 if (!p && !strcmp(c,"define_in_struct")) { 00398 Fl_Type *t = Fl_Type_make("class"); 00399 t->name(read_word()); 00400 Fl_Type::current = p = t; 00401 paste = 1; // stops "missing }" error 00402 continue; 00403 } 00404 00405 if (!strcmp(c,"do_not_include_H_from_C")) { 00406 include_H_from_C=0; 00407 goto CONTINUE; 00408 } 00409 if (!strcmp(c,"use_FL_COMMAND")) { 00410 use_FL_COMMAND=1; 00411 goto CONTINUE; 00412 } 00413 if (!strcmp(c,"i18n_type")) { 00414 i18n_type = atoi(read_word()); 00415 goto CONTINUE; 00416 } 00417 if (!strcmp(c,"i18n_function")) { 00418 i18n_function = strdup(read_word()); 00419 goto CONTINUE; 00420 } 00421 if (!strcmp(c,"i18n_file")) { 00422 i18n_file = strdup(read_word()); 00423 goto CONTINUE; 00424 } 00425 if (!strcmp(c,"i18n_set")) { 00426 i18n_set = strdup(read_word()); 00427 goto CONTINUE; 00428 } 00429 if (!strcmp(c,"i18n_include")) { 00430 i18n_include = strdup(read_word()); 00431 goto CONTINUE; 00432 } 00433 if (!strcmp(c,"i18n_type")) 00434 { 00435 i18n_type = atoi(read_word()); 00436 goto CONTINUE; 00437 } 00438 if (!strcmp(c,"i18n_type")) 00439 { 00440 i18n_type = atoi(read_word()); 00441 goto CONTINUE; 00442 } 00443 if (!strcmp(c,"header_name")) { 00444 if (!header_file_set) header_file_name = strdup(read_word()); 00445 else read_word(); 00446 goto CONTINUE; 00447 } 00448 00449 if (!strcmp(c,"code_name")) { 00450 if (!code_file_set) code_file_name = strdup(read_word()); 00451 else read_word(); 00452 goto CONTINUE; 00453 } 00454 00455 if (!strcmp(c, "snap") || !strcmp(c, "gridx") || !strcmp(c, "gridy")) { 00456 // grid settings are now global 00457 read_word(); 00458 goto CONTINUE; 00459 } 00460 00461 {Fl_Type *t = Fl_Type_make(c); 00462 if (!t) { 00463 read_error("Unknown word \"%s\"", c); 00464 continue; 00465 } 00466 t->name(read_word()); 00467 00468 c = read_word(1); 00469 if (strcmp(c,"{") && t->is_class()) { // <prefix> <name> 00470 ((Fl_Class_Type*)t)->prefix(t->name()); 00471 t->name(c); 00472 c = read_word(1); 00473 } 00474 00475 if (strcmp(c,"{")) { 00476 read_error("Missing property list for %s\n",t->title()); 00477 goto REUSE_C; 00478 } 00479 00480 t->open_ = 0; 00481 for (;;) { 00482 const char *cc = read_word(); 00483 if (!cc || !strcmp(cc,"}")) break; 00484 t->read_property(cc); 00485 } 00486 00487 if (!t->is_parent()) continue; 00488 c = read_word(1); 00489 if (strcmp(c,"{")) { 00490 read_error("Missing child list for %s\n",t->title()); 00491 goto REUSE_C; 00492 } 00493 read_children(t, 0);} 00494 Fl_Type::current = p; 00495 CONTINUE:; 00496 } 00497 } 00498 00499 extern void deselect(); 00500 00501 int read_file(const char *filename, int merge) { 00502 Fl_Type *o; 00503 read_version = 0.0; 00504 if (!open_read(filename)) return 0; 00505 if (merge) deselect(); else delete_all(); 00506 read_children(Fl_Type::current, merge); 00507 Fl_Type::current = 0; 00508 // Force menu items to be rebuilt... 00509 for (o = Fl_Type::first; o; o = o->next) 00510 if (o->is_menu_button()) o->add_child(0,0); 00511 for (o = Fl_Type::first; o; o = o->next) 00512 if (o->selected) {Fl_Type::current = o; break;} 00513 selection_changed(Fl_Type::current); 00514 return close_read(); 00515 } 00516 00518 // Read Forms and XForms fdesign files: 00519 00520 int read_fdesign_line(const char*& name, const char*& value) { 00521 00522 int length = 0; 00523 int x; 00524 // find a colon: 00525 for (;;) { 00526 x = getc(fin); 00527 if (x < 0 && feof(fin)) return 0; 00528 if (x == '\n') {length = 0; continue;} // no colon this line... 00529 if (!isspace(x & 255)) { 00530 buffer[length++] = x; 00531 expand_buffer(length); 00532 } 00533 if (x == ':') break; 00534 } 00535 int valueoffset = length; 00536 buffer[length-1] = 0; 00537 00538 // skip to start of value: 00539 for (;;) { 00540 x = getc(fin); 00541 if ((x < 0 && feof(fin)) || x == '\n' || !isspace(x & 255)) break; 00542 } 00543 00544 // read the value: 00545 for (;;) { 00546 if (x == '\\') {x = read_quoted(); if (x<0) continue;} 00547 else if (x == '\n') break; 00548 buffer[length++] = x; 00549 expand_buffer(length); 00550 x = getc(fin); 00551 } 00552 buffer[length] = 0; 00553 name = buffer; 00554 value = buffer+valueoffset; 00555 return 1; 00556 } 00557 00558 int fdesign_flip; 00559 int fdesign_magic; 00560 #include <FL/Fl_Group.H> 00561 00562 static const char *class_matcher[] = { 00563 "FL_CHECKBUTTON", "Fl_Check_Button", 00564 "FL_ROUNDBUTTON", "Fl_Round_Button", 00565 "FL_ROUND3DBUTTON", "Fl_Round_Button", 00566 "FL_LIGHTBUTTON", "Fl_Light_Button", 00567 "FL_FRAME", "Fl_Box", 00568 "FL_LABELFRAME", "Fl_Box", 00569 "FL_TEXT", "Fl_Box", 00570 "FL_VALSLIDER", "Fl_Value_Slider", 00571 "FL_MENU", "Fl_Menu_Button", 00572 "3", "FL_BITMAP", 00573 "1", "FL_BOX", 00574 "71","FL_BROWSER", 00575 "11","FL_BUTTON", 00576 "4", "FL_CHART", 00577 "42","FL_CHOICE", 00578 "61","FL_CLOCK", 00579 "25","FL_COUNTER", 00580 "22","FL_DIAL", 00581 "101","FL_FREE", 00582 "31","FL_INPUT", 00583 "12","Fl_Light_Button", 00584 "41","FL_MENU", 00585 "23","FL_POSITIONER", 00586 "13","Fl_Round_Button", 00587 "21","FL_SLIDER", 00588 "2", "FL_BOX", // was FL_TEXT 00589 "62","FL_TIMER", 00590 "24","Fl_Value_Slider", 00591 0}; 00592 00593 void read_fdesign() { 00594 fdesign_magic = atoi(read_word()); 00595 fdesign_flip = (fdesign_magic < 13000); 00596 Fl_Widget_Type *window = 0; 00597 Fl_Widget_Type *group = 0; 00598 Fl_Widget_Type *widget = 0; 00599 if (!Fl_Type::current) { 00600 Fl_Type *t = Fl_Type_make("Function"); 00601 t->name("create_the_forms()"); 00602 Fl_Type::current = t; 00603 } 00604 for (;;) { 00605 const char *name; 00606 const char *value; 00607 if (!read_fdesign_line(name, value)) break; 00608 00609 if (!strcmp(name,"Name")) { 00610 00611 window = (Fl_Widget_Type*)Fl_Type_make("Fl_Window"); 00612 window->name(value); 00613 window->label(value); 00614 Fl_Type::current = widget = window; 00615 00616 } else if (!strcmp(name,"class")) { 00617 00618 if (!strcmp(value,"FL_BEGIN_GROUP")) { 00619 group = widget = (Fl_Widget_Type*)Fl_Type_make("Fl_Group"); 00620 Fl_Type::current = group; 00621 } else if (!strcmp(value,"FL_END_GROUP")) { 00622 if (group) { 00623 Fl_Group* g = (Fl_Group*)(group->o); 00624 g->begin(); 00625 g->forms_end(); 00626 Fl_Group::current(0); 00627 } 00628 group = widget = 0; 00629 Fl_Type::current = window; 00630 } else { 00631 for (int i = 0; class_matcher[i]; i += 2) 00632 if (!strcmp(value,class_matcher[i])) { 00633 value = class_matcher[i+1]; break;} 00634 widget = (Fl_Widget_Type*)Fl_Type_make(value); 00635 if (!widget) { 00636 printf("class %s not found, using Fl_Button\n", value); 00637 widget = (Fl_Widget_Type*)Fl_Type_make("Fl_Button"); 00638 } 00639 } 00640 00641 } else if (widget) { 00642 if (!widget->read_fdesign(name, value)) 00643 printf("Ignoring \"%s: %s\"\n", name, value); 00644 } 00645 } 00646 } 00647 00648 // 00649 // End of "$Id: file.cxx 7903 2010-11-28 21:06:39Z matt $". 00650 //