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)  

file.cxx

Go to the documentation of this file.
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 //