2 // "$Id: file.cxx 7903 2010-11-28 21:06:39Z matt $"
4 // Fluid file routines for the Fast Light Tool Kit (FLTK).
6 // You may find the basic read_* and write_* routines to
7 // be useful for other programs. I have used them many times.
8 // They are somewhat similar to tcl, using matching { and }
11 // Copyright 1998-2010 by Bill Spitzak and others.
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Library General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Library General Public License for more details.
23 // You should have received a copy of the GNU Library General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
28 // Please report all bugs and problems on the following page:
30 // http://www.fltk.org/str.php
35 #include "../src/flstring.h"
37 #include "alignment_panel.h"
39 ////////////////////////////////////////////////////////////////
40 // BASIC FILE WRITING:
44 int open_write(const char *s
) {
45 if (!s
) {fout
= stdout
; return 1;}
46 FILE *f
= fl_fopen(s
,"w");
62 int is_id(char); // in code.C
64 // write a string, quoting characters if necessary:
65 void write_word(const char *w
) {
66 if (needspace
) putc(' ', fout
);
68 if (!w
|| !*w
) {fprintf(fout
,"{}"); return;}
70 // see if it is a single word:
71 for (p
= w
; is_id(*p
); p
++) ;
72 if (!*p
) {fprintf(fout
,"%s",w
); return;}
73 // see if there are matching braces:
75 for (p
= w
; *p
; p
++) {
77 else if (*p
== '}') {n
--; if (n
<0) break;}
79 int mismatched
= (n
!= 0);
80 // write out brace-quoted string:
86 if (!mismatched
) break;
97 // write an arbitrary formatted word, or a comment, etc:
98 void write_string(const char *format
, ...) {
100 va_start(args
, format
);
101 if (needspace
) fputc(' ',fout
);
102 vfprintf(fout
, format
, args
);
104 needspace
= !isspace(format
[strlen(format
)-1] & 255);
107 // start a new line and indent it for a given nesting level:
108 void write_indent(int n
) {
110 while (n
--) {fputc(' ',fout
); fputc(' ',fout
);}
114 // write a '{' at the given indenting level:
115 void write_open(int) {
116 if (needspace
) fputc(' ',fout
);
121 // write a '}' at the given indenting level:
122 void write_close(int n
) {
123 if (needspace
) write_indent(n
);
128 ////////////////////////////////////////////////////////////////
129 // BASIC FILE READING:
133 static const char *fname
;
135 int open_read(const char *s
) {
137 if (!s
) {fin
= stdin
; fname
= "stdin"; return 1;}
138 FILE *f
= fl_fopen(s
,"r");
154 #include <FL/fl_message.H>
156 void read_error(const char *format
, ...) {
158 va_start(args
, format
);
161 vsnprintf(buffer
, sizeof(buffer
), format
, args
);
162 fl_message("%s", buffer
);
164 fprintf(stderr
, "%s:%d: ", fname
, lineno
);
165 vfprintf(stderr
, format
, args
);
166 fprintf(stderr
, "\n");
171 static int hexdigit(int x
) {
172 if (isdigit(x
)) return x
-'0';
173 if (isupper(x
)) return x
-'A'+10;
174 if (islower(x
)) return x
-'a'+10;
179 static int read_quoted() { // read whatever character is after a \ .
181 switch(c
= fgetc(fin
)) {
182 case '\n': lineno
++; return -1;
183 case 'a' : return('\a');
184 case 'b' : return('\b');
185 case 'f' : return('\f');
186 case 'n' : return('\n');
187 case 'r' : return('\r');
188 case 't' : return('\t');
189 case 'v' : return('\v');
190 case 'x' : /* read hex */
191 for (c
=x
=0; x
<3; x
++) {
194 if (d
> 15) {ungetc(ch
,fin
); break;}
198 default: /* read octal */
199 if (c
<'0' || c
>'7') break;
201 for (x
=0; x
<2; x
++) {
204 if (d
>7) {ungetc(ch
,fin
); break;}
212 // return a word read from the file, or NULL at the EOF:
213 // This will skip all comments (# to end of line), and evaluate
214 // all \xxx sequences and use \ at the end of line to remove the newline.
215 // A word is any one of:
216 // a continuous string of non-space chars except { and } and #
217 // everything between matching {...} (unless wantbrace != 0)
218 // the characters '{' and '}'
222 static void expand_buffer(int length
) {
223 if (length
>= buflen
) {
226 buffer
= (char*)malloc(buflen
);
229 if (length
>= buflen
) buflen
= length
+1;
230 buffer
= (char *)realloc((void *)buffer
,buflen
);
235 const char *read_word(int wantbrace
) {
238 // skip all the whitespace before it:
241 if (x
< 0 && feof(fin
)) { // eof
243 } else if (x
== '#') { // comment
244 do x
= getc(fin
); while (x
>= 0 && x
!= '\n');
247 } else if (x
== '\n') {
249 } else if (!isspace(x
& 255)) {
256 if (x
== '{' && !wantbrace
) {
258 // read in whatever is between braces
263 if (x
<0) {read_error("Missing '}'"); break;}
264 else if (x
== '#') { // embedded comment
265 do x
= getc(fin
); while (x
>= 0 && x
!= '\n');
268 } else if (x
== '\n') lineno
++;
269 else if (x
== '\\') {x
= read_quoted(); if (x
<0) continue;}
270 else if (x
== '{') nesting
++;
271 else if (x
== '}') {if (!nesting
--) break;}
272 buffer
[length
++] = x
;
273 expand_buffer(length
);
278 } else if (x
== '{' || x
== '}') {
279 // all the punctuation is a word:
286 // read in an unquoted word:
289 if (x
== '\\') {x
= read_quoted(); if (x
<0) continue;}
290 else if (x
<0 || isspace(x
& 255) || x
=='{' || x
=='}' || x
=='#') break;
291 buffer
[length
++] = x
;
292 expand_buffer(length
);
302 ////////////////////////////////////////////////////////////////
305 #include "Fl_Widget_Type.h"
307 // global int variables:
308 extern int i18n_type
;
309 extern const char* i18n_include
;
310 extern const char* i18n_function
;
311 extern const char* i18n_file
;
312 extern const char* i18n_set
;
315 extern int header_file_set
;
316 extern int code_file_set
;
317 extern const char* header_file_name
;
318 extern const char* code_file_name
;
320 int write_file(const char *filename
, int selected_only
) {
321 if (!open_write(filename
)) return 0;
322 write_string("# data file for the Fltk User Interface Designer (fluid)\n"
323 "version %.4f",FL_VERSION
);
324 if(!include_H_from_C
)
325 write_string("\ndo_not_include_H_from_C");
327 write_string("\nuse_FL_COMMAND");
329 write_string("\ni18n_type %d", i18n_type
);
330 write_string("\ni18n_include %s", i18n_include
);
332 case 1 : /* GNU gettext */
333 write_string("\ni18n_function %s", i18n_function
);
335 case 2 : /* POSIX catgets */
336 if (i18n_file
[0]) write_string("\ni18n_file %s", i18n_file
);
337 write_string("\ni18n_set %s", i18n_set
);
341 if (!selected_only
) {
342 write_string("\nheader_name"); write_word(header_file_name
);
343 write_string("\ncode_name"); write_word(code_file_name
);
345 for (Fl_Type
*p
= Fl_Type::first
; p
;) {
346 if (!selected_only
|| p
->selected
) {
350 for (p
= p
->next
; p
&& p
->level
> q
; p
= p
->next
);
355 return close_write();
358 ////////////////////////////////////////////////////////////////
359 // read all the objects out of the input file:
363 extern Fl_Type
*Fl_Type_make(const char *tn
);
365 static void read_children(Fl_Type
*p
, int paste
) {
366 Fl_Type::current
= p
;
368 const char *c
= read_word();
371 if (p
&& !paste
) read_error("Missing '}'");
375 if (!strcmp(c
,"}")) {
376 if (!p
) read_error("Unexpected '}'");
380 if (!strcmp(c
,"version")) {
382 read_version
= strtod(c
,0);
383 if (read_version
<=0 || read_version
>FL_VERSION
)
384 read_error("unknown version '%s'",c
);
388 // back compatibility with Vincent Penne's original class code:
389 if (!p
&& !strcmp(c
,"define_in_struct")) {
390 Fl_Type
*t
= Fl_Type_make("class");
391 t
->name(read_word());
392 Fl_Type::current
= p
= t
;
393 paste
= 1; // stops "missing }" error
397 if (!strcmp(c
,"do_not_include_H_from_C")) {
401 if (!strcmp(c
,"use_FL_COMMAND")) {
405 if (!strcmp(c
,"i18n_type")) {
406 i18n_type
= atoi(read_word());
409 if (!strcmp(c
,"i18n_function")) {
410 i18n_function
= strdup(read_word());
413 if (!strcmp(c
,"i18n_file")) {
414 i18n_file
= strdup(read_word());
417 if (!strcmp(c
,"i18n_set")) {
418 i18n_set
= strdup(read_word());
421 if (!strcmp(c
,"i18n_include")) {
422 i18n_include
= strdup(read_word());
425 if (!strcmp(c
,"i18n_type"))
427 i18n_type
= atoi(read_word());
430 if (!strcmp(c
,"i18n_type"))
432 i18n_type
= atoi(read_word());
435 if (!strcmp(c
,"header_name")) {
436 if (!header_file_set
) header_file_name
= strdup(read_word());
441 if (!strcmp(c
,"code_name")) {
442 if (!code_file_set
) code_file_name
= strdup(read_word());
447 if (!strcmp(c
, "snap") || !strcmp(c
, "gridx") || !strcmp(c
, "gridy")) {
448 // grid settings are now global
453 {Fl_Type
*t
= Fl_Type_make(c
);
455 read_error("Unknown word \"%s\"", c
);
458 t
->name(read_word());
461 if (strcmp(c
,"{") && t
->is_class()) { // <prefix> <name>
462 ((Fl_Class_Type
*)t
)->prefix(t
->name());
468 read_error("Missing property list for %s\n",t
->title());
474 const char *cc
= read_word();
475 if (!cc
|| !strcmp(cc
,"}")) break;
476 t
->read_property(cc
);
479 if (!t
->is_parent()) continue;
482 read_error("Missing child list for %s\n",t
->title());
485 read_children(t
, 0);}
486 Fl_Type::current
= p
;
491 extern void deselect();
493 int read_file(const char *filename
, int merge
) {
496 if (!open_read(filename
)) return 0;
497 if (merge
) deselect(); else delete_all();
498 read_children(Fl_Type::current
, merge
);
499 Fl_Type::current
= 0;
500 // Force menu items to be rebuilt...
501 for (o
= Fl_Type::first
; o
; o
= o
->next
)
502 if (o
->is_menu_button()) o
->add_child(0,0);
503 for (o
= Fl_Type::first
; o
; o
= o
->next
)
504 if (o
->selected
) {Fl_Type::current
= o
; break;}
505 selection_changed(Fl_Type::current
);
510 // End of "$Id: file.cxx 7903 2010-11-28 21:06:39Z matt $".