// // String File Writer code for the Fast Light Tool Kit (FLTK). // // Copyright 1998-2025 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this // file is missing or damaged, see the license at: // // https://www.fltk.org/COPYING.php // // Please see the following page on how to report bugs and issues: // // https://www.fltk.org/bugs.php // #include "io/String_Writer.h" #include "Fluid.h" #include "Project.h" #include "nodes/Window_Node.h" #include "nodes/Function_Node.h" using namespace fld; using namespace fld::io; /** Write a string to a file, replacing all non-ASCII characters with octal codes. \param[in] out output file \param[in] text write this NUL terminated utf-8 string \return EOF if any of the file access calls failed, 0 if OK */ static int write_escaped_strings(FILE *out, const char *text) { int ret = 0; const unsigned char *utf8_text = (const unsigned char *)text; for (const unsigned char *s = utf8_text; *s; ++s) { unsigned char c = *s; // escape control characters, delete, all utf-8, and the double quotes // note: we should have an option in the project settings to allow utf-8 // characters in the output text and not escape them if (c < 32 || c > 126 || c == '\"') { if (c == '\r') { ret = fputs("\\r", out); } else if (c == '\n') { ret = fputs("\\n", out); } else { ret = fprintf(out, "\\%03o", c); } } else { ret = putc((int)c, out); } } return ret; } /** Write a file that contains all label and tooltip strings for internationalization. The user is responsible to set the right file name extension. The file format is determined by `proj_.i18n.type`. \param[in] filename file path and name to a file that will hold the strings \return 1 if the file could not be opened for writing, or the result of `fclose`. */ int fld::io::write_strings(Project &proj, const std::string &filename) { Node *p; Widget_Node *w; int i; FILE *fp = fl_fopen(filename.c_str(), "wb"); if (!fp) return 1; switch (proj.i18n.type) { case fld::I18n_Type::NONE : /* None, just put static text out */ fprintf(fp, "# generated by Fast Light User Interface Designer (fluid) version %.4f\n", FL_VERSION); for (auto w: proj.tree.all_widgets()) { if (w->label()) { write_escaped_strings(fp, w->label()); putc('\n', fp); } if (!w->tooltip().empty()) { write_escaped_strings(fp, w->tooltip().c_str()); putc('\n', fp); } } break; case fld::I18n_Type::GNU : /* GNU gettext, put a .po file out */ fprintf(fp, "# generated by Fast Light User Interface Designer (fluid) version %.4f\n", FL_VERSION); for (p = proj.tree.first; p; p = p->next) { if (p->is_widget()) { w = (Widget_Node *)p; if (w->label()) { fputs("msgid \"", fp); write_escaped_strings(fp, w->label()); fputs("\"\n", fp); fputs("msgstr \"", fp); write_escaped_strings(fp, w->label()); fputs("\"\n", fp); } if (!w->tooltip().empty()) { fputs("msgid \"", fp); write_escaped_strings(fp, w->tooltip().c_str()); fputs("\"\n", fp); fputs("msgstr \"", fp); write_escaped_strings(fp, w->tooltip().c_str()); fputs("\"\n", fp); } } } break; case fld::I18n_Type::POSIX : /* POSIX catgets, put a .msg file out */ fprintf(fp, "$ generated by Fast Light User Interface Designer (fluid) version %.4f\n", FL_VERSION); fprintf(fp, "$set %s\n", proj.i18n.posix_set.c_str()); fputs("$quote \"\n", fp); for (i = 1, p = proj.tree.first; p; p = p->next) { if (p->is_widget()) { w = (Widget_Node *)p; if (w->label()) { fprintf(fp, "%d \"", i ++); write_escaped_strings(fp, w->label()); fputs("\"\n", fp); } if (!w->tooltip().empty()) { fprintf(fp, "%d \"", i ++); write_escaped_strings(fp, w->tooltip().c_str()); fputs("\"\n", fp); } } } break; } return fclose(fp); }