From 1985aefc0e502048f92b91beef87c0dfbe669fed Mon Sep 17 00:00:00 2001 From: Matthias Melcher Date: Fri, 7 Mar 2025 16:34:35 +0100 Subject: Restructuring Fluid source files. --- fluid/code.cxx | 1107 -------------------------------------------------------- 1 file changed, 1107 deletions(-) delete mode 100644 fluid/code.cxx (limited to 'fluid/code.cxx') diff --git a/fluid/code.cxx b/fluid/code.cxx deleted file mode 100644 index 3c789abd3..000000000 --- a/fluid/code.cxx +++ /dev/null @@ -1,1107 +0,0 @@ -// -// Code output routines for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2024 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 "code.h" - -#include "fluid.h" -#include "Fl_Group_Type.h" -#include "Fl_Window_Type.h" -#include "Fl_Function_Type.h" -#include "file.h" -#include "undo.h" - -#include -#include -#include -#include "fluid_filename.h" -#include "../src/flstring.h" - -#include -#include -#include - -#include - -/// \defgroup cfile C Code File Operations -/// \{ - - -/** - Return true if c can be in a C identifier. - I needed this so it is not messed up by locale settings. - \param[in] c a character, or the start of a utf-8 sequence - \return 1 if c is alphanumeric or '_' - */ -int is_id(char c) { - return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_'; -} - -/** - 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 - */ -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 `g_project.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 write_strings(const std::string &filename) { - Fl_Type *p; - Fl_Widget_Type *w; - int i; - - FILE *fp = fl_fopen(filename.c_str(), "wb"); - if (!fp) return 1; - - switch (g_project.i18n_type) { - case FD_I18N_NONE : /* None, just put static text out */ - fprintf(fp, "# generated by Fast Light User Interface Designer (fluid) version %.4f\n", - FL_VERSION); - for (p = Fl_Type::first; p; p = p->next) { - if (p->is_widget()) { - w = (Fl_Widget_Type *)p; - - if (w->label()) { - write_escaped_strings(fp, w->label()); - putc('\n', fp); - } - - if (w->tooltip()) { - write_escaped_strings(fp, w->tooltip()); - putc('\n', fp); - } - } - } - break; - case FD_I18N_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 = Fl_Type::first; p; p = p->next) { - if (p->is_widget()) { - w = (Fl_Widget_Type *)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()) { - fputs("msgid \"", fp); - write_escaped_strings(fp, w->tooltip()); - fputs("\"\n", fp); - - fputs("msgstr \"", fp); - write_escaped_strings(fp, w->tooltip()); - fputs("\"\n", fp); - } - } - } - break; - case FD_I18N_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", g_project.i18n_pos_set.c_str()); - fputs("$quote \"\n", fp); - - for (i = 1, p = Fl_Type::first; p; p = p->next) { - if (p->is_widget()) { - w = (Fl_Widget_Type *)p; - - if (w->label()) { - fprintf(fp, "%d \"", i ++); - write_escaped_strings(fp, w->label()); - fputs("\"\n", fp); - } - - if (w->tooltip()) { - fprintf(fp, "%d \"", i ++); - write_escaped_strings(fp, w->tooltip()); - fputs("\"\n", fp); - } - } - } - break; - } - - return fclose(fp); -} - -//////////////////////////////////////////////////////////////// -// Generate unique but human-readable identifiers: - -/** A binary searchable tree storing identifiers for quick retrieval. */ -struct Fd_Identifier_Tree { - char* text; - void* object; - Fd_Identifier_Tree *left, *right; - Fd_Identifier_Tree (const char* t, void* o) : text(fl_strdup(t)), object(o) {left = right = 0;} - ~Fd_Identifier_Tree(); -}; - -Fd_Identifier_Tree::~Fd_Identifier_Tree() { - delete left; - free((void *)text); - delete right; -} - -/** \brief Return a unique name for the given object. - - This function combines the name and label into an identifier. It then checks - if that id was already taken by another object, and if so, appends a - hexadecimal value which is incremented until the id is unique in this file. - - If a new id was created, it is stored in the id tree. - - \param[in] o create an ID for this object - \param[in] type is the first word of the ID - \param[in] name if name is set, it is appended to the ID - \param[in] label else if label is set, it is appended, skipping non-keyword characters - \return buffer to a unique identifier, managed by Fd_Code_Writer, so caller must NOT free() it - */ -const char* Fd_Code_Writer::unique_id(void* o, const char* type, const char* name, const char* label) { - char buffer[128]; - char* q = buffer; - char* q_end = q + 128 - 8 - 1; // room for hex number and NUL - while (*type) *q++ = *type++; - *q++ = '_'; - const char* n = name; - if (!n || !*n) n = label; - if (n && *n) { - while (*n && !is_id(*n)) n++; - while (is_id(*n) && (q < q_end)) *q++ = *n++; - } - *q = 0; - // okay, search the tree and see if the name was already used: - Fd_Identifier_Tree** p = &id_root; - int which = 0; - while (*p) { - int i = strcmp(buffer, (*p)->text); - if (!i) { - if ((*p)->object == o) return (*p)->text; - // already used, we need to pick a new name: - sprintf(q,"%x",++which); - p = &id_root; - continue; - } - else if (i < 0) p = &((*p)->left); - else p = &((*p)->right); - } - *p = new Fd_Identifier_Tree(buffer, o); - return (*p)->text; -} - -//////////////////////////////////////////////////////////////// -// return current indentation: - - -/** - Return a C string that indents code to the given depth. - - Indentation can be changed by modifying the multiplicator (``*2`` to keep - the FLTK indent style). Changing `spaces` to a list of tabs would generate - tab indents instead. This function can also be used for fixed depth indents - in the header file. - - Do *not* ever make this a user preference, or you will end up writing a - fully featured code formatter. - - \param[in] set generate this indent depth - \return pointer to a static string - */ -const char *Fd_Code_Writer::indent(int set) { - static const char* spaces = " "; - int i = set * 2; - if (i>32) i = 32; - if (i<0) i = 0; - return spaces+32-i; -} - -/** - Return a C string that indents code to the current source file depth. - \return pointer to a static string - */ -const char *Fd_Code_Writer::indent() { - return indent(indentation); -} - -/** - Return a C string that indents code to the current source file depth plus an offset. - \param[in] offset adds a temporary offset for this call only; this does not - change the `indentation` variable; offset can be negative - \return pointer to a static string - */ -const char *Fd_Code_Writer::indent_plus(int offset) { - return indent(indentation+offset); -} - - -//////////////////////////////////////////////////////////////// -// declarations/include files: -// Each string generated by write_h_once is written only once to -// the header file. This is done by keeping a binary tree of all -// the calls so far and not printing it if it is in the tree. - -/** A binary searchable tree storing text for quick retrieval. */ -struct Fd_Text_Tree { - char *text; - Fd_Text_Tree *left, *right; - Fd_Text_Tree(const char *t) { - text = fl_strdup(t); - left = right = 0; - } - ~Fd_Text_Tree(); -}; - -Fd_Text_Tree::~Fd_Text_Tree() { - delete left; - free((void *)text); - delete right; -} - -/** A binary searchable tree storing pointers for quick retrieval. */ -struct Fd_Pointer_Tree { - void *ptr; - Fd_Pointer_Tree *left, *right; - Fd_Pointer_Tree(void *p) { - ptr = p; - left = right = 0; - } - ~Fd_Pointer_Tree(); -}; - -Fd_Pointer_Tree::~Fd_Pointer_Tree() { - delete left; - delete right; -} - -/** - Print a formatted line to the header file, unless the same line was produced before in this header file. - \note Resulting line is cropped at 1023 bytes. - \param[in] format printf-style formatting text, followed by a vararg list - \return 1 if the text was written to the file, 0 if it was previously written. - */ -int Fd_Code_Writer::write_h_once(const char *format, ...) { - va_list args; - char buf[1024]; - va_start(args, format); - vsnprintf(buf, sizeof(buf), format, args); - va_end(args); - Fd_Text_Tree **p = &text_in_header; - while (*p) { - int i = strcmp(buf,(*p)->text); - if (!i) return 0; - else if (i < 0) p = &((*p)->left); - else p = &((*p)->right); - } - fprintf(header_file,"%s\n",buf); - *p = new Fd_Text_Tree(buf); - return 1; -} - -/** - Print a formatted line to the source file, unless the same line was produced before in this code file. - \note Resulting line is cropped at 1023 bytes. - \param[in] format printf-style formatting text, followed by a vararg list - \return 1 if the text was written to the file, 0 if it was previously written. - */ -int Fd_Code_Writer::write_c_once(const char *format, ...) { - va_list args; - char buf[1024]; - va_start(args, format); - vsnprintf(buf, sizeof(buf), format, args); - va_end(args); - Fd_Text_Tree **p = &text_in_header; - while (*p) { - int i = strcmp(buf,(*p)->text); - if (!i) return 0; - else if (i < 0) p = &((*p)->left); - else p = &((*p)->right); - } - p = &text_in_code; - while (*p) { - int i = strcmp(buf,(*p)->text); - if (!i) return 0; - else if (i < 0) p = &((*p)->left); - else p = &((*p)->right); - } - crc_printf("%s\n", buf); - *p = new Fd_Text_Tree(buf); - return 1; -} - -/** - Return true if this pointer was already included in the code file. - If it was not, add it to the list and return false. - \param[in] pp ay pointer - \return true if found in the tree, false if added to the tree - */ -bool Fd_Code_Writer::c_contains(void *pp) { - Fd_Pointer_Tree **p = &ptr_in_code; - while (*p) { - if ((*p)->ptr == pp) return true; - else if ((*p)->ptr < pp) p = &((*p)->left); - else p = &((*p)->right); - } - *p = new Fd_Pointer_Tree(pp); - return false; -} - -/** - Write a C string to the code file, escaping non-ASCII characters. - - Text is broken into lines of 78 character. - FLUID " before and after every line text. - - A list of control characters and ", ', and \\ are escaped by adding a \\ in - front of them. Escape ?? by writing ?\\?. All other characters that are not - between 32 and 126 inclusive will be escaped as octal characters. - - This function is utf8 agnostic. - - \param[in] s write this string - \param[in] length write so many bytes in this string - - \see f.write_cstring(const char*) - */ -void Fd_Code_Writer::write_cstring(const char *s, int length) { - const char *next_line = "\"\n\""; - if (varused_test) { - varused = 1; - return; - } - // if we are rendering to the source code preview window, and the text is - // longer than four lines, we only render a placeholder. - if (write_codeview && ((s==NULL) || (length>300))) { - if (length>=0) - crc_printf("\" ... %d bytes of text... \"", length); - else - crc_puts("\" ... text... \""); - return; - } - if (length==-1 || s==0L) { - crc_puts("\n#error string not found\n"); - crc_puts("\" ... undefined size text... \""); - return; - } - - const char *p = s; - const char *e = s+length; - int linelength = 1; - crc_putc('\"'); - for (; p < e;) { - int c = *p++; - switch (c) { - case '\b': c = 'b'; goto QUOTED; - case '\t': c = 't'; goto QUOTED; - case '\n': c = 'n'; goto QUOTED; - case '\f': c = 'f'; goto QUOTED; - case '\r': c = 'r'; goto QUOTED; - case '\"': - case '\'': - case '\\': - QUOTED: - if (linelength >= 77) { crc_puts(next_line); linelength = 0; } - crc_putc('\\'); - crc_putc(c); - linelength += 2; - break; - case '?': // prevent trigraphs by writing ?? as ?\? - if (p-2 >= s && *(p-2) == '?') goto QUOTED; - // else fall through: - default: - if (c >= ' ' && c < 127) { - // a legal ASCII character - if (linelength >= 78) { crc_puts(next_line); linelength = 0; } - crc_putc(c); - linelength++; - break; - } - // if the UTF-8 option is checked, write unicode characters verbatim - if (g_project.utf8_in_src && (c&0x80)) { - if ((c&0x40)) { - // This is the first character in a utf-8 sequence (0b11......). - // A line break would be ok here. Do not put linebreak in front of - // following characters (0b10......) - if (linelength >= 78) { crc_puts(next_line); linelength = 0; } - } - crc_putc(c); - linelength++; - break; - } - // otherwise we must print it as an octal constant: - c &= 255; - if (linelength >= 74) { crc_puts(next_line); linelength = 0; } - crc_printf("\\%03o", c); - linelength += 4; - break; - } - } - crc_putc('\"'); -} - -/** - Write a C string, escaping non-ASCII characters. - \param[in] s write this string - \see f.write_cstring(const char*, int) - */ -void Fd_Code_Writer::write_cstring(const char *s) { - write_cstring(s, (int)strlen(s)); -} - -/** - Write an array of C binary data (does not add a null). - The output is bracketed in { and }. The content is written - as decimal bytes, i.e. `{ 1, 2, 200 }` - - \param[in] s a block of binary data, interpreted as unsigned bytes - \param[in] length size of the block in bytes - */ -void Fd_Code_Writer::write_cdata(const char *s, int length) { - if (varused_test) { - varused = 1; - return; - } - if (write_codeview) { - if (length>=0) - crc_printf("{ /* ... %d bytes of binary data... */ }", length); - else - crc_puts("{ /* ... binary data... */ }"); - return; - } - if (length==-1) { - crc_puts("\n#error data not found\n"); - crc_puts("{ /* ... undefined size binary data... */ }"); - return; - } - const unsigned char *w = (const unsigned char *)s; - const unsigned char *e = w+length; - int linelength = 1; - crc_putc('{'); - for (; w < e;) { - unsigned char c = *w++; - if (c>99) linelength += 4; - else if (c>9) linelength += 3; - else linelength += 2; - if (linelength >= 77) {crc_puts("\n"); linelength = 0;} - crc_printf("%d", c); - if (wis_a(ID_Function) - || t->is_a(ID_Decl) - || t->is_a(ID_Data); -// || t->is_a(ID_Class) // FLUID can't handle a class inside a class -// || t->is_a(ID_Widget_Class) -// || t->is_a(ID_DeclBlock) // Declaration blocks are generally not handled well -} - -/** - Return true, if this is a comment, and if it is followed by a class member. - This must only be called if q is inside a widget class. - Widget classes can have widgets and members (functions/methods, declarations, - etc.) intermixed. - \param[in] q should be a comment type - \return true if this comment is followed by a class member - \return false if it is followed by a widget or code - \see is_class_member(Fl_Type *t) - */ -bool is_comment_before_class_member(Fl_Type *q) { - if (q->is_a(ID_Comment) && q->next && q->next->level==q->level) { - if (q->next->is_a(ID_Comment)) - return is_comment_before_class_member(q->next); - if (is_class_member(q->next)) - return true; - } - return false; -} - -/** - Recursively write static code and declarations - \param[in] p write this type and all its children - \return pointer to the next sibling - */ -Fl_Type* Fd_Code_Writer::write_static(Fl_Type* p) { - if (write_codeview) p->header_static_start = (int)ftell(header_file); - if (write_codeview) p->code_static_start = (int)ftell(code_file); - p->write_static(*this); - if (write_codeview) p->code_static_end = (int)ftell(code_file); - if (write_codeview) p->header_static_end = (int)ftell(header_file); - - Fl_Type* q; - for (q = p->next; q && q->level > p->level;) { - q = write_static(q); - } - - p->write_static_after(*this); - - return q; -} - -/** - Recursively write code, putting children between the two parts of the parent code. - \param[in] p write this type and all its children - \return pointer to the next sibling - */ -Fl_Type* Fd_Code_Writer::write_code(Fl_Type* p) { - // write all code that comes before the children code - // (but don't write the last comment until the very end) - if (!(p==Fl_Type::last && p->is_a(ID_Comment))) { - if (write_codeview) p->code1_start = (int)ftell(code_file); - if (write_codeview) p->header1_start = (int)ftell(header_file); - p->write_code1(*this); - if (write_codeview) p->code1_end = (int)ftell(code_file); - if (write_codeview) p->header1_end = (int)ftell(header_file); - } - // recursively write the code of all children - Fl_Type* q; - if (p->is_widget() && p->is_class()) { - // Handle widget classes specially - for (q = p->next; q && q->level > p->level;) { - // note: maybe declaration blocks should be handled like comments in the context - if (!is_class_member(q) && !is_comment_before_class_member(q)) { - q = write_code(q); - } else { - int level = q->level; - do { - q = q->next; - } while (q && q->level > level); - } - } - - // write all code that come after the children - if (write_codeview) p->code2_start = (int)ftell(code_file); - if (write_codeview) p->header2_start = (int)ftell(header_file); - p->write_code2(*this); - if (write_codeview) p->code2_end = (int)ftell(code_file); - if (write_codeview) p->header2_end = (int)ftell(header_file); - - for (q = p->next; q && q->level > p->level;) { - if (is_class_member(q) || is_comment_before_class_member(q)) { - q = write_code(q); - } else { - int level = q->level; - do { - q = q->next; - } while (q && q->level > level); - } - } - - write_h("};\n"); - current_widget_class = 0L; - } else { - for (q = p->next; q && q->level > p->level;) q = write_code(q); - // write all code that come after the children - if (write_codeview) p->code2_start = (int)ftell(code_file); - if (write_codeview) p->header2_start = (int)ftell(header_file); - p->write_code2(*this); - if (write_codeview) p->code2_end = (int)ftell(code_file); - if (write_codeview) p->header2_end = (int)ftell(header_file); - } - return q; -} - -/** - Write the source and header files for the current design. - - If the files already exist, they will be overwritten. - - \note There is no true error checking here. - - \param[in] s filename of source code file - \param[in] t filename of the header file - \return 0 if the operation failed, 1 if it was successful - */ -int Fd_Code_Writer::write_code(const char *s, const char *t, bool to_codeview) { - write_codeview = to_codeview; - delete id_root; id_root = 0; - indentation = 0; - current_class = 0L; - current_widget_class = 0L; - if (!s) code_file = stdout; - else { - FILE *f = fl_fopen(s, "wb"); - if (!f) return 0; - code_file = f; - } - if (!t) header_file = stdout; - else { - FILE *f = fl_fopen(t, "wb"); - if (!f) {fclose(code_file); return 0;} - header_file = f; - } - // Remember the last code file location for MergeBack - if (s && g_project.write_mergeback_data && !to_codeview) { - std::string proj_filename = g_project.projectfile_path() + g_project.projectfile_name(); - int i, n = (int)proj_filename.size(); - for (i=0; iis_a(ID_Comment)) { - if (write_codeview) { - first_type->code1_start = first_type->code2_start = (int)ftell(code_file); - first_type->header1_start = first_type->header2_start = (int)ftell(header_file); - } - // it is ok to write non-recursive code here, because comments have no children or code2 blocks - first_type->write_code1(*this); - if (write_codeview) { - first_type->code1_end = first_type->code2_end = (int)ftell(code_file); - first_type->header1_end = first_type->header2_end = (int)ftell(header_file); - } - first_type = first_type->next; - } - - const char *hdr = "\ -// generated by Fast Light User Interface Designer (fluid) version %.4f\n\n"; - fprintf(header_file, hdr, FL_VERSION); - crc_printf(hdr, FL_VERSION); - - {char define_name[102]; - const char* a = fl_filename_name(t); - char* b = define_name; - if (!isalpha(*a)) {*b++ = '_';} - while (*a) {*b++ = isalnum(*a) ? *a : '_'; a++;} - *b = 0; - fprintf(header_file, "#ifndef %s\n", define_name); - fprintf(header_file, "#define %s\n", define_name); - } - - if (g_project.avoid_early_includes==0) { - write_h_once("#include "); - } - if (t && g_project.include_H_from_C) { - if (to_codeview) { - write_c("#include \"CodeView.h\"\n"); - } else if (g_project.header_file_name[0] == '.' && strchr(g_project.header_file_name.c_str(), '/') == NULL) { - write_c("#include \"%s\"\n", fl_filename_name(t)); - } else { - write_c("#include \"%s\"\n", g_project.header_file_name.c_str()); - } - } - std::string loc_include, loc_conditional; - if (g_project.i18n_type==FD_I18N_GNU) { - loc_include = g_project.i18n_gnu_include; - loc_conditional = g_project.i18n_gnu_conditional; - } else { - loc_include = g_project.i18n_pos_include; - loc_conditional = g_project.i18n_pos_conditional; - } - if (g_project.i18n_type && !loc_include.empty()) { - int conditional = !loc_conditional.empty(); - if (conditional) { - write_c("#ifdef %s\n", loc_conditional.c_str()); - indentation++; - } - if (loc_include[0] != '<' && loc_include[0] != '\"') - write_c("#%sinclude \"%s\"\n", indent(), loc_include.c_str()); - else - write_c("#%sinclude %s\n", indent(), loc_include.c_str()); - if (g_project.i18n_type == FD_I18N_POSIX) { - if (!g_project.i18n_pos_file.empty()) { - write_c("extern nl_catd %s;\n", g_project.i18n_pos_file.c_str()); - } else { - write_c("// Initialize I18N stuff now for menus...\n"); - write_c("#%sinclude \n", indent()); - write_c("static char *_locale = setlocale(LC_MESSAGES, \"\");\n"); - write_c("static nl_catd _catalog = catopen(\"%s\", 0);\n", g_project.basename().c_str()); - } - } - if (conditional) { - write_c("#else\n"); - if (g_project.i18n_type == FD_I18N_GNU) { - if (!g_project.i18n_gnu_function.empty()) { - write_c("#%sifndef %s\n", indent(), g_project.i18n_gnu_function.c_str()); - write_c("#%sdefine %s(text) text\n", indent_plus(1), g_project.i18n_gnu_function.c_str()); - write_c("#%sendif\n", indent()); - } - } - if (g_project.i18n_type == FD_I18N_POSIX) { - write_c("#%sifndef catgets\n", indent()); - write_c("#%sdefine catgets(catalog, set, msgid, text) text\n", indent_plus(1)); - write_c("#%sendif\n", indent()); - } - indentation--; - write_c("#endif\n"); - } - if (g_project.i18n_type == FD_I18N_GNU && g_project.i18n_gnu_static_function[0]) { - write_c("#ifndef %s\n", g_project.i18n_gnu_static_function.c_str()); - write_c("#%sdefine %s(text) text\n", indent_plus(1), g_project.i18n_gnu_static_function.c_str()); - write_c("#endif\n"); - } - } - for (Fl_Type* p = first_type; p;) { - // write all static data for this & all children first - write_static(p); - // then write the nested code: - p = write_code(p); - } - - if (!s) return 1; - - fprintf(header_file, "#endif\n"); - - Fl_Type* last_type = Fl_Type::last; - if (last_type && (last_type != Fl_Type::first) && last_type->is_a(ID_Comment)) { - if (write_codeview) { - last_type->code1_start = last_type->code2_start = (int)ftell(code_file); - last_type->header1_start = last_type->header2_start = (int)ftell(header_file); - } - last_type->write_code1(*this); - if (write_codeview) { - last_type->code1_end = last_type->code2_end = (int)ftell(code_file); - last_type->header1_end = last_type->header2_end = (int)ftell(header_file); - } - } - int x = 0, y = 0; - - if (code_file != stdout) - x = fclose(code_file); - code_file = 0; - if (header_file != stdout) - y = fclose(header_file); - header_file = 0; - return x >= 0 && y >= 0; -} - - -/** - Write the public/private/protected keywords inside the class. - This avoids repeating these words if the mode is already set. - \param[in] state 0 for private, 1 for public, 2 for protected - */ -void Fd_Code_Writer::write_public(int state) { - if (!current_class && !current_widget_class) return; - if (current_class && current_class->write_public_state == state) return; - if (current_widget_class && current_widget_class->write_public_state == state) return; - if (current_class) current_class->write_public_state = state; - if (current_widget_class) current_widget_class->write_public_state = state; - switch (state) { - case 0: write_h("private:\n"); break; - case 1: write_h("public:\n"); break; - case 2: write_h("protected:\n"); break; - } -} - -/** - Create and initialize a new C++ source code writer. - */ -Fd_Code_Writer::Fd_Code_Writer() -: code_file(NULL), - header_file(NULL), - id_root(NULL), - text_in_header(NULL), - text_in_code(NULL), - ptr_in_code(NULL), - block_crc_(0), - block_line_start_(true), - block_buffer_(NULL), - block_buffer_size_(0), - indentation(0), - write_codeview(false), - varused_test(0), - varused(0) -{ - block_crc_ = crc32(0, NULL, 0); -} - -/** - Release all resources. - */ -Fd_Code_Writer::~Fd_Code_Writer() -{ - delete id_root; - delete ptr_in_code; - delete text_in_code; - delete text_in_header; - if (block_buffer_) ::free(block_buffer_); -} - -/** - Write a MergeBack tag as a separate line of C++ comment. - The tag contains information about the type of tag that we are writing, a - link back to the type using its unique id, and the CRC of all code written - after the previous tag up to this point. - \param[in] type FD_TAG_GENERIC, FD_TAG_CODE, FD_TAG_MENU_CALLBACK, or FD_TAG_WIDGET_CALLBACK - \param[in] uid the unique id of the current type - */ -void Fd_Code_Writer::tag(int type, unsigned short uid) { - if (g_project.write_mergeback_data) - fprintf(code_file, "//~fl~%d~%04x~%08x~~\n", type, (int)uid, (unsigned int)block_crc_); - block_crc_ = crc32(0, NULL, 0); -} - -/** - Static function to calculate the CRC32 of a block of C source code. - Calculation of the CRC ignores leading whitespace in a line and all linefeed - characters ('\\r'). - \param[in] data a pointer to the data block - \param[in] n the size of the data in bytes, or -1 to use strlen() - \param[in] in_crc add to this CRC, 0 by default to start a new block - \param[inout] inout_line_start optional pointer to flag that determines - if we are the start of a line, used to find leading whitespace - \return the new CRC - */ -unsigned long Fd_Code_Writer::block_crc(const void *data, int n, unsigned long in_crc, bool *inout_line_start) { - if (!data) return 0; - if (n==-1) n = (int)strlen((const char*)data); - bool line_start = true; - if (inout_line_start) line_start = *inout_line_start; - const char *s = (const char*)data; - for ( ; n>0; --n, ++s) { - if (line_start) { - // don't count leading spaces and tabs in a line - while (n>0 && *s>0 && isspace(*s)) { s++; n--; } - if (*s) line_start = false; - } - // don't count '\r' that may be introduced by Windows - if (n>0 && *s=='\r') { s++; n--; } - if (n>0 && *s=='\n') line_start = true; - if (n>0) { - in_crc = crc32(in_crc, (const Bytef*)s, 1); - } - } - if (inout_line_start) *inout_line_start = line_start; - return in_crc; -} - -/** Add the following block of text to the CRC of this class. - \param[in] data a pointer to the data block - \param[in] n the size of the data in bytes, or -1 to use strlen() - */ -void Fd_Code_Writer::crc_add(const void *data, int n) { - block_crc_ = block_crc(data, n, block_crc_, &block_line_start_); -} - -/** Write formatted text to the code file. - If MergeBack is enabled, the CRC calculation is continued. - \param[in] format printf style formatting string - \return see fprintf(FILE *, *const char*, ...) - */ -int Fd_Code_Writer::crc_printf(const char *format, ...) { - va_list args; - va_start(args, format); - int ret = crc_vprintf(format, args); - va_end(args); - return ret; -} - -/** Write formatted text to the code file. - If MergeBack is enabled, the CRC calculation is continued. - \param[in] format printf style formatting string - \param[in] args list of arguments - \return see fprintf(FILE *, *const char*, ...) - */ -int Fd_Code_Writer::crc_vprintf(const char *format, va_list args) { - if (g_project.write_mergeback_data) { - int n = vsnprintf(block_buffer_, block_buffer_size_, format, args); - if (n > block_buffer_size_) { - block_buffer_size_ = n + 128; - if (block_buffer_) ::free(block_buffer_); - block_buffer_ = (char*)::malloc(block_buffer_size_+1); - n = vsnprintf(block_buffer_, block_buffer_size_, format, args); - } - crc_add(block_buffer_, n); - return fputs(block_buffer_, code_file); - } else { - return vfprintf(code_file, format, args); - } -} - -/** Write some text to the code file. - If MergeBack is enabled, the CRC calculation is continued. - \param[in] text any text, no requirements to end in a newline or such - \return see fputs(const char*, FILE*) - */ -int Fd_Code_Writer::crc_puts(const char *text) { - if (g_project.write_mergeback_data) { - crc_add(text); - } - return fputs(text, code_file); -} - -/** Write a single ASCII character to the code file. - If MergeBack is enabled, the CRC calculation is continued. - \note to write UTF-8 characters, use Fd_Code_Writer::crc_puts(const char *text) - \param[in] c any character between 0 and 127 inclusive - \return see fputc(int, FILE*) - */ -int Fd_Code_Writer::crc_putc(int c) { - if (g_project.write_mergeback_data) { - uchar uc = (uchar)c; - crc_add(&uc, 1); - } - return fputc(c, code_file); -} - -/// \} - -- cgit v1.2.3