You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

512 lines
12KB

  1. //
  2. // "$Id: file.cxx 7903 2010-11-28 21:06:39Z matt $"
  3. //
  4. // Fluid file routines for the Fast Light Tool Kit (FLTK).
  5. //
  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 }
  9. // to quote strings.
  10. //
  11. // Copyright 1998-2010 by Bill Spitzak and others.
  12. //
  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.
  17. //
  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.
  22. //
  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
  26. // USA.
  27. //
  28. // Please report all bugs and problems on the following page:
  29. //
  30. // http://www.fltk.org/str.php
  31. //
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include "../src/flstring.h"
  35. #include <stdarg.h>
  36. #include "alignment_panel.h"
  37. ////////////////////////////////////////////////////////////////
  38. // BASIC FILE WRITING:
  39. static FILE *fout;
  40. int open_write(const char *s) {
  41. if (!s) {fout = stdout; return 1;}
  42. FILE *f = fl_fopen(s,"w");
  43. if (!f) return 0;
  44. fout = f;
  45. return 1;
  46. }
  47. int close_write() {
  48. if (fout != stdout) {
  49. int x = fclose(fout);
  50. fout = stdout;
  51. return x >= 0;
  52. }
  53. return 1;
  54. }
  55. static int needspace;
  56. int is_id(char); // in code.C
  57. // write a string, quoting characters if necessary:
  58. void write_word(const char *w) {
  59. if (needspace) putc(' ', fout);
  60. needspace = 1;
  61. if (!w || !*w) {fprintf(fout,"{}"); return;}
  62. const char *p;
  63. // see if it is a single word:
  64. for (p = w; is_id(*p); p++) ;
  65. if (!*p) {fprintf(fout,"%s",w); return;}
  66. // see if there are matching braces:
  67. int n = 0;
  68. for (p = w; *p; p++) {
  69. if (*p == '{') n++;
  70. else if (*p == '}') {n--; if (n<0) break;}
  71. }
  72. int mismatched = (n != 0);
  73. // write out brace-quoted string:
  74. putc('{', fout);
  75. for (; *w; w++) {
  76. switch (*w) {
  77. case '{':
  78. case '}':
  79. if (!mismatched) break;
  80. case '\\':
  81. case '#':
  82. putc('\\',fout);
  83. break;
  84. }
  85. putc(*w,fout);
  86. }
  87. putc('}', fout);
  88. }
  89. // write an arbitrary formatted word, or a comment, etc:
  90. void write_string(const char *format, ...) {
  91. va_list args;
  92. va_start(args, format);
  93. if (needspace) fputc(' ',fout);
  94. vfprintf(fout, format, args);
  95. va_end(args);
  96. needspace = !isspace(format[strlen(format)-1] & 255);
  97. }
  98. // start a new line and indent it for a given nesting level:
  99. void write_indent(int n) {
  100. fputc('\n',fout);
  101. while (n--) {fputc(' ',fout); fputc(' ',fout);}
  102. needspace = 0;
  103. }
  104. // write a '{' at the given indenting level:
  105. void write_open(int) {
  106. if (needspace) fputc(' ',fout);
  107. fputc('{',fout);
  108. needspace = 0;
  109. }
  110. // write a '}' at the given indenting level:
  111. void write_close(int n) {
  112. if (needspace) write_indent(n);
  113. fputc('}',fout);
  114. needspace = 1;
  115. }
  116. ////////////////////////////////////////////////////////////////
  117. // BASIC FILE READING:
  118. static FILE *fin;
  119. static int lineno;
  120. static const char *fname;
  121. int open_read(const char *s) {
  122. lineno = 1;
  123. if (!s) {fin = stdin; fname = "stdin"; return 1;}
  124. FILE *f = fl_fopen(s,"r");
  125. if (!f) return 0;
  126. fin = f;
  127. fname = s;
  128. return 1;
  129. }
  130. int close_read() {
  131. if (fin != stdin) {
  132. int x = fclose(fin);
  133. fin = 0;
  134. return x >= 0;
  135. }
  136. return 1;
  137. }
  138. #include <FL/fl_message.H>
  139. void read_error(const char *format, ...) {
  140. va_list args;
  141. va_start(args, format);
  142. if (!fin) {
  143. char buffer[1024];
  144. vsnprintf(buffer, sizeof(buffer), format, args);
  145. fl_message("%s", buffer);
  146. } else {
  147. fprintf(stderr, "%s:%d: ", fname, lineno);
  148. vfprintf(stderr, format, args);
  149. fprintf(stderr, "\n");
  150. }
  151. va_end(args);
  152. }
  153. static int hexdigit(int x) {
  154. if (isdigit(x)) return x-'0';
  155. if (isupper(x)) return x-'A'+10;
  156. if (islower(x)) return x-'a'+10;
  157. return 20;
  158. }
  159. static int read_quoted() { // read whatever character is after a \ .
  160. int c,d,x;
  161. switch(c = fgetc(fin)) {
  162. case '\n': lineno++; return -1;
  163. case 'a' : return('\a');
  164. case 'b' : return('\b');
  165. case 'f' : return('\f');
  166. case 'n' : return('\n');
  167. case 'r' : return('\r');
  168. case 't' : return('\t');
  169. case 'v' : return('\v');
  170. case 'x' : /* read hex */
  171. for (c=x=0; x<3; x++) {
  172. int ch = fgetc(fin);
  173. d = hexdigit(ch);
  174. if (d > 15) {ungetc(ch,fin); break;}
  175. c = (c<<4)+d;
  176. }
  177. break;
  178. default: /* read octal */
  179. if (c<'0' || c>'7') break;
  180. c -= '0';
  181. for (x=0; x<2; x++) {
  182. int ch = fgetc(fin);
  183. d = hexdigit(ch);
  184. if (d>7) {ungetc(ch,fin); break;}
  185. c = (c<<3)+d;
  186. }
  187. break;
  188. }
  189. return(c);
  190. }
  191. // return a word read from the file, or NULL at the EOF:
  192. // This will skip all comments (# to end of line), and evaluate
  193. // all \xxx sequences and use \ at the end of line to remove the newline.
  194. // A word is any one of:
  195. // a continuous string of non-space chars except { and } and #
  196. // everything between matching {...} (unless wantbrace != 0)
  197. // the characters '{' and '}'
  198. static char *buffer;
  199. static int buflen;
  200. static void expand_buffer(int length) {
  201. if (length >= buflen) {
  202. if (!buflen) {
  203. buflen = length+1;
  204. buffer = (char*)malloc(buflen);
  205. } else {
  206. buflen = 2*buflen;
  207. if (length >= buflen) buflen = length+1;
  208. buffer = (char *)realloc((void *)buffer,buflen);
  209. }
  210. }
  211. }
  212. const char *read_word(int wantbrace) {
  213. int x;
  214. // skip all the whitespace before it:
  215. for (;;) {
  216. x = getc(fin);
  217. if (x < 0 && feof(fin)) { // eof
  218. return 0;
  219. } else if (x == '#') { // comment
  220. do x = getc(fin); while (x >= 0 && x != '\n');
  221. lineno++;
  222. continue;
  223. } else if (x == '\n') {
  224. lineno++;
  225. } else if (!isspace(x & 255)) {
  226. break;
  227. }
  228. }
  229. expand_buffer(100);
  230. if (x == '{' && !wantbrace) {
  231. // read in whatever is between braces
  232. int length = 0;
  233. int nesting = 0;
  234. for (;;) {
  235. x = getc(fin);
  236. if (x<0) {read_error("Missing '}'"); break;}
  237. else if (x == '#') { // embedded comment
  238. do x = getc(fin); while (x >= 0 && x != '\n');
  239. lineno++;
  240. continue;
  241. } else if (x == '\n') lineno++;
  242. else if (x == '\\') {x = read_quoted(); if (x<0) continue;}
  243. else if (x == '{') nesting++;
  244. else if (x == '}') {if (!nesting--) break;}
  245. buffer[length++] = x;
  246. expand_buffer(length);
  247. }
  248. buffer[length] = 0;
  249. return buffer;
  250. } else if (x == '{' || x == '}') {
  251. // all the punctuation is a word:
  252. buffer[0] = x;
  253. buffer[1] = 0;
  254. return buffer;
  255. } else {
  256. // read in an unquoted word:
  257. int length = 0;
  258. for (;;) {
  259. if (x == '\\') {x = read_quoted(); if (x<0) continue;}
  260. else if (x<0 || isspace(x & 255) || x=='{' || x=='}' || x=='#') break;
  261. buffer[length++] = x;
  262. expand_buffer(length);
  263. x = getc(fin);
  264. }
  265. ungetc(x, fin);
  266. buffer[length] = 0;
  267. return buffer;
  268. }
  269. }
  270. ////////////////////////////////////////////////////////////////
  271. #include <FL/Fl.H>
  272. #include "Fl_Widget_Type.h"
  273. // global int variables:
  274. extern int i18n_type;
  275. extern const char* i18n_include;
  276. extern const char* i18n_function;
  277. extern const char* i18n_file;
  278. extern const char* i18n_set;
  279. extern int header_file_set;
  280. extern int code_file_set;
  281. extern const char* header_file_name;
  282. extern const char* code_file_name;
  283. int write_file(const char *filename, int selected_only) {
  284. if (!open_write(filename)) return 0;
  285. write_string("# data file for the Fltk User Interface Designer (fluid)\n"
  286. "version %.4f",FL_VERSION);
  287. if(!include_H_from_C)
  288. write_string("\ndo_not_include_H_from_C");
  289. if(use_FL_COMMAND)
  290. write_string("\nuse_FL_COMMAND");
  291. if (i18n_type) {
  292. write_string("\ni18n_type %d", i18n_type);
  293. write_string("\ni18n_include %s", i18n_include);
  294. switch (i18n_type) {
  295. case 1 : /* GNU gettext */
  296. write_string("\ni18n_function %s", i18n_function);
  297. break;
  298. case 2 : /* POSIX catgets */
  299. if (i18n_file[0]) write_string("\ni18n_file %s", i18n_file);
  300. write_string("\ni18n_set %s", i18n_set);
  301. break;
  302. }
  303. }
  304. if (!selected_only) {
  305. write_string("\nheader_name"); write_word(header_file_name);
  306. write_string("\ncode_name"); write_word(code_file_name);
  307. }
  308. for (Fl_Type *p = Fl_Type::first; p;) {
  309. if (!selected_only || p->selected) {
  310. p->write();
  311. write_string("\n");
  312. int q = p->level;
  313. for (p = p->next; p && p->level > q; p = p->next);
  314. } else {
  315. p = p->next;
  316. }
  317. }
  318. return close_write();
  319. }
  320. ////////////////////////////////////////////////////////////////
  321. // read all the objects out of the input file:
  322. double read_version;
  323. extern Fl_Type *Fl_Type_make(const char *tn);
  324. static void read_children(Fl_Type *p, int paste) {
  325. Fl_Type::current = p;
  326. for (;;) {
  327. const char *c = read_word();
  328. REUSE_C:
  329. if (!c) {
  330. if (p && !paste) read_error("Missing '}'");
  331. break;
  332. }
  333. if (!strcmp(c,"}")) {
  334. if (!p) read_error("Unexpected '}'");
  335. break;
  336. }
  337. if (!strcmp(c,"version")) {
  338. c = read_word();
  339. read_version = strtod(c,0);
  340. if (read_version<=0 || read_version>FL_VERSION)
  341. read_error("unknown version '%s'",c);
  342. continue;
  343. }
  344. // back compatibility with Vincent Penne's original class code:
  345. if (!p && !strcmp(c,"define_in_struct")) {
  346. Fl_Type *t = Fl_Type_make("class");
  347. t->name(read_word());
  348. Fl_Type::current = p = t;
  349. paste = 1; // stops "missing }" error
  350. continue;
  351. }
  352. if (!strcmp(c,"do_not_include_H_from_C")) {
  353. include_H_from_C=0;
  354. goto CONTINUE;
  355. }
  356. if (!strcmp(c,"use_FL_COMMAND")) {
  357. use_FL_COMMAND=1;
  358. goto CONTINUE;
  359. }
  360. if (!strcmp(c,"i18n_type")) {
  361. i18n_type = atoi(read_word());
  362. goto CONTINUE;
  363. }
  364. if (!strcmp(c,"i18n_function")) {
  365. i18n_function = strdup(read_word());
  366. goto CONTINUE;
  367. }
  368. if (!strcmp(c,"i18n_file")) {
  369. i18n_file = strdup(read_word());
  370. goto CONTINUE;
  371. }
  372. if (!strcmp(c,"i18n_set")) {
  373. i18n_set = strdup(read_word());
  374. goto CONTINUE;
  375. }
  376. if (!strcmp(c,"i18n_include")) {
  377. i18n_include = strdup(read_word());
  378. goto CONTINUE;
  379. }
  380. if (!strcmp(c,"i18n_type"))
  381. {
  382. i18n_type = atoi(read_word());
  383. goto CONTINUE;
  384. }
  385. if (!strcmp(c,"i18n_type"))
  386. {
  387. i18n_type = atoi(read_word());
  388. goto CONTINUE;
  389. }
  390. if (!strcmp(c,"header_name")) {
  391. if (!header_file_set) header_file_name = strdup(read_word());
  392. else read_word();
  393. goto CONTINUE;
  394. }
  395. if (!strcmp(c,"code_name")) {
  396. if (!code_file_set) code_file_name = strdup(read_word());
  397. else read_word();
  398. goto CONTINUE;
  399. }
  400. if (!strcmp(c, "snap") || !strcmp(c, "gridx") || !strcmp(c, "gridy")) {
  401. // grid settings are now global
  402. read_word();
  403. goto CONTINUE;
  404. }
  405. {Fl_Type *t = Fl_Type_make(c);
  406. if (!t) {
  407. read_error("Unknown word \"%s\"", c);
  408. continue;
  409. }
  410. t->name(read_word());
  411. c = read_word(1);
  412. if (strcmp(c,"{") && t->is_class()) { // <prefix> <name>
  413. ((Fl_Class_Type*)t)->prefix(t->name());
  414. t->name(c);
  415. c = read_word(1);
  416. }
  417. if (strcmp(c,"{")) {
  418. read_error("Missing property list for %s\n",t->title());
  419. goto REUSE_C;
  420. }
  421. t->open_ = 0;
  422. for (;;) {
  423. const char *cc = read_word();
  424. if (!cc || !strcmp(cc,"}")) break;
  425. t->read_property(cc);
  426. }
  427. if (!t->is_parent()) continue;
  428. c = read_word(1);
  429. if (strcmp(c,"{")) {
  430. read_error("Missing child list for %s\n",t->title());
  431. goto REUSE_C;
  432. }
  433. read_children(t, 0);}
  434. Fl_Type::current = p;
  435. CONTINUE:;
  436. }
  437. }
  438. extern void deselect();
  439. int read_file(const char *filename, int merge) {
  440. Fl_Type *o;
  441. read_version = 0.0;
  442. if (!open_read(filename)) return 0;
  443. if (merge) deselect(); else delete_all();
  444. read_children(Fl_Type::current, merge);
  445. Fl_Type::current = 0;
  446. // Force menu items to be rebuilt...
  447. for (o = Fl_Type::first; o; o = o->next)
  448. if (o->is_menu_button()) o->add_child(0,0);
  449. for (o = Fl_Type::first; o; o = o->next)
  450. if (o->selected) {Fl_Type::current = o; break;}
  451. selection_changed(Fl_Type::current);
  452. return close_read();
  453. }
  454. //
  455. // End of "$Id: file.cxx 7903 2010-11-28 21:06:39Z matt $".
  456. //