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.

604 lines
16KB

  1. //
  2. // "$Id: code.cxx 7903 2010-11-28 21:06:39Z matt $"
  3. //
  4. // Code output routines for the Fast Light Tool Kit (FLTK).
  5. //
  6. // Copyright 1998-2010 by Bill Spitzak and others.
  7. //
  8. // This library is free software; you can redistribute it and/or
  9. // modify it under the terms of the GNU Library General Public
  10. // License as published by the Free Software Foundation; either
  11. // version 2 of the License, or (at your option) any later version.
  12. //
  13. // This library is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. // Library General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Library General Public
  19. // License along with this library; if not, write to the Free Software
  20. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  21. // USA.
  22. //
  23. // Please report all bugs and problems on the following page:
  24. //
  25. // http://www.fltk.org/str.php
  26. //
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include "../src/flstring.h"
  30. #include <stdarg.h>
  31. #include <FL/Fl.H>
  32. #include "Fl_Type.h"
  33. #include "alignment_panel.h"
  34. static FILE *code_file;
  35. static FILE *header_file;
  36. extern char i18n_program[];
  37. extern int i18n_type;
  38. extern const char* i18n_include;
  39. extern const char* i18n_function;
  40. extern const char* i18n_file;
  41. extern const char* i18n_set;
  42. // return true if c can be in a C identifier. I needed this so
  43. // it is not messed up by locale settings:
  44. int is_id(char c) {
  45. return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_';
  46. }
  47. ////////////////////////////////////////////////////////////////
  48. // Generate unique but human-readable identifiers:
  49. struct id {
  50. char* text;
  51. void* object;
  52. id *left, *right;
  53. id (const char* t, void* o) : text(strdup(t)), object(o) {left = right = 0;}
  54. ~id();
  55. };
  56. id::~id() {
  57. delete left;
  58. free((void *)text);
  59. delete right;
  60. }
  61. static id* id_root;
  62. const char* unique_id(void* o, const char* type, const char* name, const char* label) {
  63. char buffer[128];
  64. char* q = buffer;
  65. while (*type) *q++ = *type++;
  66. *q++ = '_';
  67. const char* n = name;
  68. if (!n || !*n) n = label;
  69. if (n && *n) {
  70. while (*n && !is_id(*n)) n++;
  71. while (is_id(*n)) *q++ = *n++;
  72. }
  73. *q = 0;
  74. // okay, search the tree and see if the name was already used:
  75. id** p = &id_root;
  76. int which = 0;
  77. while (*p) {
  78. int i = strcmp(buffer, (*p)->text);
  79. if (!i) {
  80. if ((*p)->object == o) return (*p)->text;
  81. // already used, we need to pick a new name:
  82. sprintf(q,"%x",++which);
  83. p = &id_root;
  84. continue;
  85. }
  86. else if (i < 0) p = &((*p)->left);
  87. else p = &((*p)->right);
  88. }
  89. *p = new id(buffer, o);
  90. return (*p)->text;
  91. }
  92. ////////////////////////////////////////////////////////////////
  93. // return current indentation:
  94. static const char* spaces = " ";
  95. int indentation;
  96. const char* indent() {
  97. int i = indentation; if (i>16) i = 16;
  98. return spaces+16-i;
  99. }
  100. ////////////////////////////////////////////////////////////////
  101. // declarations/include files:
  102. // Each string generated by write_declare is written only once to
  103. // the header file. This is done by keeping a binary tree of all
  104. // the calls so far and not printing it if it is in the tree.
  105. struct included {
  106. char *text;
  107. included *left, *right;
  108. included(const char *t) {
  109. text = strdup(t);
  110. left = right = 0;
  111. }
  112. ~included();
  113. };
  114. included::~included() {
  115. delete left;
  116. free((void *)text);
  117. delete right;
  118. }
  119. static included *included_root;
  120. int write_declare(const char *format, ...) {
  121. va_list args;
  122. char buf[1024];
  123. va_start(args, format);
  124. vsnprintf(buf, sizeof(buf), format, args);
  125. va_end(args);
  126. included **p = &included_root;
  127. while (*p) {
  128. int i = strcmp(buf,(*p)->text);
  129. if (!i) return 0;
  130. else if (i < 0) p = &((*p)->left);
  131. else p = &((*p)->right);
  132. }
  133. fprintf(header_file,"%s\n",buf);
  134. *p = new included(buf);
  135. return 1;
  136. }
  137. ////////////////////////////////////////////////////////////////
  138. // silly thing to prevent declaring unused variables:
  139. // When this symbol is on, all attempts to write code don't write
  140. // anything, but set a variable if it looks like the variable "o" is used:
  141. int varused_test;
  142. int varused;
  143. // write an array of C characters (adds a null):
  144. void write_cstring(const char *w, int length) {
  145. if (varused_test) {
  146. varused = 1;
  147. return;
  148. }
  149. const char *e = w+length;
  150. int linelength = 1;
  151. putc('\"', code_file);
  152. for (; w < e;) {
  153. int c = *w++;
  154. switch (c) {
  155. case '\b': c = 'b'; goto QUOTED;
  156. case '\t': c = 't'; goto QUOTED;
  157. case '\n': c = 'n'; goto QUOTED;
  158. case '\f': c = 'f'; goto QUOTED;
  159. case '\r': c = 'r'; goto QUOTED;
  160. case '\"':
  161. case '\'':
  162. case '\\':
  163. QUOTED:
  164. if (linelength >= 77) {fputs("\\\n",code_file); linelength = 0;}
  165. putc('\\', code_file);
  166. putc(c, code_file);
  167. linelength += 2;
  168. break;
  169. case '?': // prevent trigraphs by writing ?? as ?\?
  170. if (*(w-2) == '?') goto QUOTED;
  171. // else fall through:
  172. default:
  173. if (c >= ' ' && c < 127) {
  174. // a legal ASCII character
  175. if (linelength >= 78) {fputs("\\\n",code_file); linelength = 0;}
  176. putc(c, code_file);
  177. linelength++;
  178. break;
  179. }
  180. // otherwise we must print it as an octal constant:
  181. c &= 255;
  182. if (c < 8) {
  183. if (linelength >= 76) {fputs("\\\n",code_file); linelength = 0;}
  184. fprintf(code_file, "\\%o",c);
  185. linelength += 2;
  186. } else if (c < 64) {
  187. if (linelength >= 75) {fputs("\\\n",code_file); linelength = 0;}
  188. fprintf(code_file, "\\%o",c);
  189. linelength += 3;
  190. } else {
  191. if (linelength >= 74) {fputs("\\\n",code_file); linelength = 0;}
  192. fprintf(code_file, "\\%o",c);
  193. linelength += 4;
  194. }
  195. // We must not put more numbers after it, because some C compilers
  196. // consume them as part of the quoted sequence. Use string constant
  197. // pasting to avoid this:
  198. c = *w;
  199. if (w < e && ( (c>='0'&&c<='9') || (c>='a'&&c<='f') || (c>='A'&&c<='F') )) {
  200. putc('\"', code_file); linelength++;
  201. if (linelength >= 79) {fputs("\n",code_file); linelength = 0;}
  202. putc('\"', code_file); linelength++;
  203. }
  204. break;
  205. }
  206. }
  207. putc('\"', code_file);
  208. }
  209. // write a C string, quoting characters if necessary:
  210. void write_cstring(const char *w) {write_cstring(w,strlen(w));}
  211. // write an array of C binary data (does not add a null):
  212. void write_cdata(const char *s, int length) {
  213. if (varused_test) {
  214. varused = 1;
  215. return;
  216. }
  217. if (write_sourceview) {
  218. if (length>=0)
  219. fprintf(code_file, "{ /* ... %d bytes of binary data... */ }", length);
  220. else
  221. fprintf(code_file, "{ /* ... binary data... */ }");
  222. return;
  223. }
  224. if (length==-1) {
  225. fprintf(code_file, "{ /* ... undefined size binary data... */ }");
  226. return;
  227. }
  228. const unsigned char *w = (const unsigned char *)s;
  229. const unsigned char *e = w+length;
  230. int linelength = 1;
  231. putc('{', code_file);
  232. for (; w < e;) {
  233. unsigned char c = *w++;
  234. if (c>99) linelength += 4;
  235. else if (c>9) linelength += 3;
  236. else linelength += 2;
  237. if (linelength >= 77) {fputs("\n",code_file); linelength = 0;}
  238. fprintf(code_file, "%d", c);
  239. if (w<e) putc(',', code_file);
  240. }
  241. putc('}', code_file);
  242. }
  243. void write_c(const char* format,...) {
  244. if (varused_test) {
  245. varused = 1;
  246. return;
  247. }
  248. va_list args;
  249. va_start(args, format);
  250. vfprintf(code_file, format, args);
  251. va_end(args);
  252. }
  253. void write_h(const char* format,...) {
  254. if (varused_test) return;
  255. va_list args;
  256. va_start(args, format);
  257. vfprintf(header_file, format, args);
  258. va_end(args);
  259. }
  260. #include <FL/filename.H>
  261. int write_number;
  262. int write_sourceview;
  263. extern Fl_Widget_Class_Type *current_widget_class;
  264. // recursively dump code, putting children between the two parts
  265. // of the parent code:
  266. static Fl_Type* write_code(Fl_Type* p) {
  267. if (write_sourceview) {
  268. p->code_position = (int)ftell(code_file);
  269. if (p->header_position_end==-1)
  270. p->header_position = (int)ftell(header_file);
  271. }
  272. // write all code that come before the children code
  273. // (but don't write the last comment until the very end)
  274. if (!(p==Fl_Type::last && p->is_comment()))
  275. p->write_code1();
  276. // recursively write the code of all children
  277. Fl_Type* q;
  278. if (p->is_widget() && p->is_class()) {
  279. // Handle widget classes specially
  280. for (q = p->next; q && q->level > p->level;) {
  281. if (strcmp(q->type_name(), "Function")) q = write_code(q);
  282. else {
  283. int level = q->level;
  284. do {
  285. q = q->next;
  286. } while (q && q->level > level);
  287. }
  288. }
  289. // write all code that come after the children
  290. p->write_code2();
  291. for (q = p->next; q && q->level > p->level;) {
  292. if (!strcmp(q->type_name(), "Function")) q = write_code(q);
  293. else {
  294. int level = q->level;
  295. do {
  296. q = q->next;
  297. } while (q && q->level > level);
  298. }
  299. }
  300. write_h("};\n");
  301. current_widget_class = 0L;
  302. } else {
  303. for (q = p->next; q && q->level > p->level;) q = write_code(q);
  304. // write all code that come after the children
  305. p->write_code2();
  306. }
  307. if (write_sourceview) {
  308. p->code_position_end = (int)ftell(code_file);
  309. if (p->header_position_end==-1)
  310. p->header_position_end = (int)ftell(header_file);
  311. }
  312. return q;
  313. }
  314. extern const char* header_file_name;
  315. extern Fl_Class_Type *current_class;
  316. int write_code(const char *s, const char *t) {
  317. const char *filemode = "w";
  318. if (write_sourceview)
  319. filemode = "wb";
  320. write_number++;
  321. delete id_root; id_root = 0;
  322. indentation = 0;
  323. current_class = 0L;
  324. current_widget_class = 0L;
  325. if (!s) code_file = stdout;
  326. else {
  327. FILE *f = fl_fopen(s, filemode);
  328. if (!f) return 0;
  329. code_file = f;
  330. }
  331. if (!t) header_file = stdout;
  332. else {
  333. FILE *f = fl_fopen(t, filemode);
  334. if (!f) {fclose(code_file); return 0;}
  335. header_file = f;
  336. }
  337. // if the first entry in the Type tree is a comment, then it is probably
  338. // a copyright notice. We print that before anything else in the file!
  339. Fl_Type* first_type = Fl_Type::first;
  340. if (first_type && first_type->is_comment()) {
  341. if (write_sourceview) {
  342. first_type->code_position = (int)ftell(code_file);
  343. first_type->header_position = (int)ftell(header_file);
  344. }
  345. // it is ok to write non-recusive code here, because comments have no children or code2 blocks
  346. first_type->write_code1();
  347. if (write_sourceview) {
  348. first_type->code_position_end = (int)ftell(code_file);
  349. first_type->header_position_end = (int)ftell(header_file);
  350. }
  351. first_type = first_type->next;
  352. }
  353. const char *hdr = "\
  354. // generated by Fast Light User Interface Designer (fluid) version %.4f\n\n";
  355. fprintf(header_file, hdr, FL_VERSION);
  356. fprintf(code_file, hdr, FL_VERSION);
  357. {char define_name[102];
  358. const char* a = fl_filename_name(t);
  359. char* b = define_name;
  360. if (!isalpha(*a)) {*b++ = '_';}
  361. while (*a) {*b++ = isalnum(*a) ? *a : '_'; a++;}
  362. *b = 0;
  363. fprintf(header_file, "#ifndef %s\n", define_name);
  364. fprintf(header_file, "#define %s\n", define_name);
  365. }
  366. write_declare("#include <FL/Fl.H>");
  367. if (i18n_type && i18n_include[0]) {
  368. if (i18n_include[0] != '<' &&
  369. i18n_include[0] != '\"')
  370. write_c("#include \"%s\"\n", i18n_include);
  371. else
  372. write_c("#include %s\n", i18n_include);
  373. if (i18n_type == 2) {
  374. if (i18n_file[0]) write_c("extern nl_catd %s;\n", i18n_file);
  375. else {
  376. write_c("// Initialize I18N stuff now for menus...\n");
  377. write_c("#include <locale.h>\n");
  378. write_c("static char *_locale = setlocale(LC_MESSAGES, \"\");\n");
  379. write_c("static nl_catd _catalog = catopen(\"%s\", 0);\n",
  380. i18n_program);
  381. }
  382. }
  383. }
  384. if (t && include_H_from_C) {
  385. if (*header_file_name == '.' && strchr(header_file_name, '/') == NULL) {
  386. write_c("#include \"%s\"\n", fl_filename_name(t));
  387. } else {
  388. write_c("#include \"%s\"\n", t);
  389. }
  390. }
  391. for (Fl_Type* p = first_type; p;) {
  392. // write all static data for this & all children first
  393. if (write_sourceview) p->header_position = (int)ftell(header_file);
  394. p->write_static();
  395. if (write_sourceview) {
  396. p->header_position_end = (int)ftell(header_file);
  397. if (p->header_position==p->header_position_end) p->header_position_end = -1;
  398. }
  399. for (Fl_Type* q = p->next; q && q->level > p->level; q = q->next) {
  400. if (write_sourceview) q->header_position = (int)ftell(header_file);
  401. q->write_static();
  402. if (write_sourceview) {
  403. q->header_position_end = (int)ftell(header_file);
  404. if (q->header_position==q->header_position_end) q->header_position_end = -1;
  405. }
  406. }
  407. // then write the nested code:
  408. p = write_code(p);
  409. }
  410. delete included_root; included_root = 0;
  411. if (!s) return 1;
  412. fprintf(header_file, "#endif\n");
  413. Fl_Type* last_type = Fl_Type::last;
  414. if (last_type && last_type->is_comment()) {
  415. if (write_sourceview) {
  416. last_type->code_position = (int)ftell(code_file);
  417. last_type->header_position = (int)ftell(header_file);
  418. }
  419. last_type->write_code1();
  420. if (write_sourceview) {
  421. last_type->code_position_end = (int)ftell(code_file);
  422. last_type->header_position_end = (int)ftell(header_file);
  423. }
  424. }
  425. int x = fclose(code_file);
  426. code_file = 0;
  427. int y = fclose(header_file);
  428. header_file = 0;
  429. return x >= 0 && y >= 0;
  430. }
  431. int write_strings(const char *sfile) {
  432. FILE *fp = fl_fopen(sfile, "w");
  433. Fl_Type *p;
  434. Fl_Widget_Type *w;
  435. int i;
  436. if (!fp) return 1;
  437. switch (i18n_type) {
  438. case 0 : /* None, just put static text out */
  439. fprintf(fp, "# generated by Fast Light User Interface Designer (fluid) version %.4f\n",
  440. FL_VERSION);
  441. for (p = Fl_Type::first; p; p = p->next) {
  442. if (p->is_widget()) {
  443. w = (Fl_Widget_Type *)p;
  444. if (w->label()) {
  445. for (const char *s = w->label(); *s; s ++)
  446. if (*s < 32 || *s > 126 || *s == '\"')
  447. fprintf(fp, "\\%03o", *s);
  448. else
  449. putc(*s, fp);
  450. putc('\n', fp);
  451. }
  452. if (w->tooltip()) {
  453. for (const char *s = w->tooltip(); *s; s ++)
  454. if (*s < 32 || *s > 126 || *s == '\"')
  455. fprintf(fp, "\\%03o", *s);
  456. else
  457. putc(*s, fp);
  458. putc('\n', fp);
  459. }
  460. }
  461. }
  462. break;
  463. case 1 : /* GNU gettext, put a .po file out */
  464. fprintf(fp, "# generated by Fast Light User Interface Designer (fluid) version %.4f\n",
  465. FL_VERSION);
  466. for (p = Fl_Type::first; p; p = p->next) {
  467. if (p->is_widget()) {
  468. w = (Fl_Widget_Type *)p;
  469. if (w->label()) {
  470. const char *s;
  471. fputs("msgid \"", fp);
  472. for (s = w->label(); *s; s ++)
  473. if (*s < 32 || *s > 126 || *s == '\"')
  474. fprintf(fp, "\\%03o", *s);
  475. else
  476. putc(*s, fp);
  477. fputs("\"\n", fp);
  478. fputs("msgstr \"", fp);
  479. for (s = w->label(); *s; s ++)
  480. if (*s < 32 || *s > 126 || *s == '\"')
  481. fprintf(fp, "\\%03o", *s);
  482. else
  483. putc(*s, fp);
  484. fputs("\"\n", fp);
  485. }
  486. if (w->tooltip()) {
  487. const char *s;
  488. fputs("msgid \"", fp);
  489. for (s = w->tooltip(); *s; s ++)
  490. if (*s < 32 || *s > 126 || *s == '\"')
  491. fprintf(fp, "\\%03o", *s);
  492. else
  493. putc(*s, fp);
  494. fputs("\"\n", fp);
  495. fputs("msgstr \"", fp);
  496. for (s = w->tooltip(); *s; s ++)
  497. if (*s < 32 || *s > 126 || *s == '\"')
  498. fprintf(fp, "\\%03o", *s);
  499. else
  500. putc(*s, fp);
  501. fputs("\"\n", fp);
  502. }
  503. }
  504. }
  505. break;
  506. case 2 : /* POSIX catgets, put a .msg file out */
  507. fprintf(fp, "$ generated by Fast Light User Interface Designer (fluid) version %.4f\n",
  508. FL_VERSION);
  509. fprintf(fp, "$set %s\n", i18n_set);
  510. fputs("$quote \"\n", fp);
  511. for (i = 1, p = Fl_Type::first; p; p = p->next) {
  512. if (p->is_widget()) {
  513. w = (Fl_Widget_Type *)p;
  514. if (w->label()) {
  515. fprintf(fp, "%d \"", i ++);
  516. for (const char *s = w->label(); *s; s ++)
  517. if (*s < 32 || *s > 126 || *s == '\"')
  518. fprintf(fp, "\\%03o", *s);
  519. else
  520. putc(*s, fp);
  521. fputs("\"\n", fp);
  522. }
  523. if (w->tooltip()) {
  524. fprintf(fp, "%d \"", i ++);
  525. for (const char *s = w->tooltip(); *s; s ++)
  526. if (*s < 32 || *s > 126 || *s == '\"')
  527. fprintf(fp, "\\%03o", *s);
  528. else
  529. putc(*s, fp);
  530. fputs("\"\n", fp);
  531. }
  532. }
  533. }
  534. break;
  535. }
  536. return fclose(fp);
  537. }
  538. ////////////////////////////////////////////////////////////////
  539. void Fl_Type::write_static() {}
  540. void Fl_Type::write_code1() {
  541. write_h("// Header for %s\n", title());
  542. write_c("// Code for %s\n", title());
  543. }
  544. void Fl_Type::write_code2() {}
  545. //
  546. // End of "$Id: code.cxx 7903 2010-11-28 21:06:39Z matt $".
  547. //