| /* ----------------------------------------------------------------------------- | |
| * This file is part of SWIG, which is licensed as a whole under version 3 | |
| * (or any later version) of the GNU General Public License. Some additional | |
| * terms also apply to certain portions of SWIG. The full details of the SWIG | |
| * license and copyrights can be found in the LICENSE and COPYRIGHT files | |
| * included with the SWIG source code as distributed by the SWIG developers | |
| * and at https://www.swig.org/legal.html. | |
| * | |
| * nested.cxx | |
| * | |
| * Nested structs support | |
| * ----------------------------------------------------------------------------- */ | |
| #include "swigmod.h" | |
| #include "cparse.h" | |
| // Nested classes processing section | |
| static Hash *classhash = 0; | |
| static String *make_name(Node *n, String *name, SwigType *decl) { | |
| int destructor = name && (*(Char(name)) == '~'); | |
| if (String *yyrename = Getattr(n, "class_rename")) { | |
| String *s = NewString(yyrename); | |
| Delattr(n, "class_rename"); | |
| if (destructor && (*(Char(s)) != '~')) { | |
| Insert(s, 0, "~"); | |
| } | |
| return s; | |
| } | |
| if (!name) | |
| return 0; | |
| return Swig_name_make(n, 0, name, decl, 0); | |
| } | |
| // C version of add_symbols() | |
| static void add_symbols_c(Node *n) { | |
| String *decl; | |
| String *wrn = 0; | |
| String *symname = 0; | |
| int iscdecl = Cmp(nodeType(n), "cdecl") == 0; | |
| Setattr(n, "ismember", "1"); | |
| Setattr(n, "access", "public"); | |
| if (Getattr(n, "sym:name")) | |
| return; | |
| decl = Getattr(n, "decl"); | |
| if (!SwigType_isfunction(decl)) { | |
| String *name = Getattr(n, "name"); | |
| String *makename = Getattr(n, "parser:makename"); | |
| if (iscdecl) { | |
| String *storage = Getattr(n, "storage"); | |
| if (Cmp(storage, "typedef") == 0) { | |
| Setattr(n, "kind", "typedef"); | |
| } else { | |
| SwigType *type = Getattr(n, "type"); | |
| String *value = Getattr(n, "value"); | |
| Setattr(n, "kind", "variable"); | |
| if (value && Len(value)) { | |
| Setattr(n, "hasvalue", "1"); | |
| } | |
| if (!type) { | |
| Printf(stderr, "notype name %s\n", name); | |
| } | |
| } | |
| } | |
| Swig_features_get(Swig_cparse_features(), 0, name, 0, n); | |
| if (makename) { | |
| symname = make_name(n, makename, 0); | |
| Delattr(n, "parser:makename"); /* temporary information, don't leave it hanging around */ | |
| } else { | |
| makename = name; | |
| symname = make_name(n, makename, 0); | |
| } | |
| if (!symname) { | |
| symname = Copy(Getattr(n, "unnamed")); | |
| } | |
| if (symname) { | |
| wrn = Swig_name_warning(n, 0, symname, 0); | |
| } | |
| } else { | |
| String *name = Getattr(n, "name"); | |
| SwigType *fdecl = Copy(decl); | |
| SwigType *fun = SwigType_pop_function(fdecl); | |
| if (iscdecl) { | |
| Setattr(n, "kind", "function"); | |
| } | |
| Swig_features_get(Swig_cparse_features(), 0, name, fun, n); | |
| symname = make_name(n, name, fun); | |
| wrn = Swig_name_warning(n, 0, symname, fun); | |
| Delete(fdecl); | |
| Delete(fun); | |
| } | |
| if (!symname) | |
| return; | |
| if (GetFlag(n, "feature:ignore")) { | |
| /* Only add to C symbol table and continue */ | |
| Swig_symbol_add(0, n); | |
| } else if (strncmp(Char(symname), "$ignore", 7) == 0) { | |
| char *c = Char(symname) + 7; | |
| SetFlag(n, "feature:ignore"); | |
| if (strlen(c)) { | |
| SWIG_WARN_NODE_BEGIN(n); | |
| Swig_warning(0, Getfile(n), Getline(n), "%s\n", c + 1); | |
| SWIG_WARN_NODE_END(n); | |
| } | |
| Swig_symbol_add(0, n); | |
| } else { | |
| Node *c; | |
| if ((wrn) && (Len(wrn))) { | |
| String *metaname = symname; | |
| if (!Getmeta(metaname, "already_warned")) { | |
| SWIG_WARN_NODE_BEGIN(n); | |
| Swig_warning(0, Getfile(n), Getline(n), "%s\n", wrn); | |
| SWIG_WARN_NODE_END(n); | |
| Setmeta(metaname, "already_warned", "1"); | |
| } | |
| } | |
| c = Swig_symbol_add(symname, n); | |
| if (c != n) { | |
| /* symbol conflict attempting to add in the new symbol */ | |
| if (Getattr(n, "sym:weak")) { | |
| Setattr(n, "sym:name", symname); | |
| } else { | |
| int inclass = 1; | |
| Swig_symbol_conflict_warn(n, c, symname, inclass); | |
| } | |
| } | |
| } | |
| Delete(symname); | |
| } | |
| /* Strips C-style and C++-style comments from string in-place. */ | |
| static void strip_comments(char *string) { | |
| int state = 0; | |
| /* | |
| * 0 - not in comment | |
| * 1 - in c-style comment | |
| * 2 - in c++-style comment | |
| * 3 - in string | |
| * 4 - after reading / not in comments | |
| * 5 - after reading * in c-style comments | |
| * 6 - after reading \ in strings | |
| */ | |
| char *c = string; | |
| while (*c) { | |
| switch (state) { | |
| case 0: | |
| if (*c == '\"') | |
| state = 3; | |
| else if (*c == '/') | |
| state = 4; | |
| break; | |
| case 1: | |
| if (*c == '*') | |
| state = 5; | |
| *c = ' '; | |
| break; | |
| case 2: | |
| if (*c == '\n') | |
| state = 0; | |
| else | |
| *c = ' '; | |
| break; | |
| case 3: | |
| if (*c == '\"') | |
| state = 0; | |
| else if (*c == '\\') | |
| state = 6; | |
| break; | |
| case 4: | |
| if (*c == '/') { | |
| *(c - 1) = ' '; | |
| *c = ' '; | |
| state = 2; | |
| } else if (*c == '*') { | |
| *(c - 1) = ' '; | |
| *c = ' '; | |
| state = 1; | |
| } else | |
| state = 0; | |
| break; | |
| case 5: | |
| if (*c == '/') | |
| state = 0; | |
| else | |
| state = 1; | |
| *c = ' '; | |
| break; | |
| case 6: | |
| state = 3; | |
| break; | |
| } | |
| ++c; | |
| } | |
| } | |
| // Create a %insert with a typedef to make a new name visible to C | |
| static Node *create_insert(Node *n, bool noTypedef = false) { | |
| // format a typedef | |
| String *ccode = Getattr(n, "code"); | |
| Push(ccode, " "); | |
| if (noTypedef) { | |
| Push(ccode, Getattr(n, "name")); | |
| Push(ccode, " "); | |
| Push(ccode, Getattr(n, "kind")); | |
| } else { | |
| Push(ccode, Getattr(n, "kind")); | |
| Push(ccode, "typedef "); | |
| Append(ccode, " "); | |
| Append(ccode, Getattr(n, "tdname")); | |
| } | |
| Append(ccode, ";"); | |
| /* Strip comments - further code may break in presence of comments. */ | |
| strip_comments(Char(ccode)); | |
| /* Make all SWIG created typedef structs/unions/classes unnamed else | |
| redefinition errors occur - nasty hack alert. */ | |
| if (!noTypedef) { | |
| const char *types_array[3] = {"struct", "union", "class"}; | |
| for (int i = 0; i < 3; i++) { | |
| char *code_ptr = Char(ccode); | |
| while (code_ptr) { | |
| /* Replace struct name (as in 'struct name {...}' ) with whitespace | |
| name will be between struct and opening brace */ | |
| code_ptr = strstr(code_ptr, types_array[i]); | |
| if (code_ptr) { | |
| char *open_bracket_pos; | |
| code_ptr += strlen(types_array[i]); | |
| open_bracket_pos = strchr(code_ptr, '{'); | |
| if (open_bracket_pos) { | |
| /* Make sure we don't have something like struct A a; */ | |
| char *semi_colon_pos = strchr(code_ptr, ';'); | |
| if (!(semi_colon_pos && (semi_colon_pos < open_bracket_pos))) | |
| while (code_ptr < open_bracket_pos) | |
| *code_ptr++ = ' '; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| { | |
| /* Remove SWIG directive %constant which may be left in the SWIG created typedefs */ | |
| char *code_ptr = Char(ccode); | |
| while (code_ptr) { | |
| code_ptr = strstr(code_ptr, "%constant"); | |
| if (code_ptr) { | |
| char *directive_end_pos = strchr(code_ptr, ';'); | |
| if (directive_end_pos) { | |
| while (code_ptr <= directive_end_pos) | |
| *code_ptr++ = ' '; | |
| } | |
| } | |
| } | |
| } | |
| Node *newnode = NewHash(); | |
| set_nodeType(newnode, "insert"); | |
| Setfile(newnode, Getfile(n)); | |
| Setline(newnode, Getline(n)); | |
| String *code = NewStringEmpty(); | |
| Wrapper_pretty_print(ccode, code); | |
| Setattr(newnode, "code", code); | |
| Delete(code); | |
| Delattr(n, "code"); | |
| return newnode; | |
| } | |
| static void insertNodeAfter(Node *n, Node *c) { | |
| Node *g = parentNode(n); | |
| set_parentNode(c, g); | |
| Node *ns = nextSibling(n); | |
| if (Node *outer = Getattr(c, "nested:outer")) { | |
| while (ns && outer == Getattr(ns, "nested:outer")) { | |
| n = ns; | |
| ns = nextSibling(n); | |
| } | |
| } | |
| if (!ns) { | |
| set_lastChild(g, c); | |
| } else { | |
| set_nextSibling(c, ns); | |
| set_previousSibling(ns, c); | |
| } | |
| set_nextSibling(n, c); | |
| set_previousSibling(c, n); | |
| } | |
| void Swig_nested_name_unnamed_c_structs(Node *n) { | |
| if (!n) | |
| return; | |
| if (!classhash) | |
| classhash = Getattr(n, "classes"); | |
| Node *c = firstChild(n); | |
| while (c) { | |
| Node *next = nextSibling(c); | |
| if (String *declName = Getattr(c, "nested:unnamed")) { | |
| if (Node *outer = Getattr(c, "nested:outer")) { | |
| // generate a name | |
| String *name = NewStringf("%s_%s", Getattr(outer, "name"), declName); | |
| Delattr(c, "nested:unnamed"); | |
| // set the name to the class and symbol table | |
| Setattr(c, "tdname", name); | |
| Setattr(c, "name", name); | |
| Swig_symbol_setscope(Getattr(c, "symtab")); | |
| Swig_symbol_setscopename(name); | |
| // now that we have a name - gather base symbols | |
| if (List *publicBases = Getattr(c, "baselist")) { | |
| List *bases = Swig_make_inherit_list(name, publicBases, 0); | |
| Swig_inherit_base_symbols(bases); | |
| Delete(bases); | |
| } | |
| Setattr(classhash, name, c); | |
| // Merge the extension into the symbol table | |
| if (Node *am = Getattr(Swig_extend_hash(), name)) { | |
| Swig_extend_merge(c, am); | |
| Swig_extend_append_previous(c, am); | |
| Delattr(Swig_extend_hash(), name); | |
| } | |
| Swig_symbol_popscope(); | |
| // process declarations following this type (assign correct new type) | |
| SwigType *ty = Copy(name); | |
| Node *decl = nextSibling(c); | |
| List *declList = NewList(); | |
| while (decl && Getattr(decl, "nested:unnamedtype") == c) { | |
| Setattr(decl, "type", ty); | |
| Append(declList, decl); | |
| Delattr(decl, "nested:unnamedtype"); | |
| SetFlag(decl, "feature:immutable"); | |
| add_symbols_c(decl); | |
| decl = nextSibling(decl); | |
| } | |
| Delete(ty); | |
| Swig_symbol_setscope(Swig_symbol_global_scope()); | |
| add_symbols_c(c); | |
| Node *ins = create_insert(c); | |
| insertNodeAfter(c, ins); | |
| removeNode(c); | |
| insertNodeAfter(n, c); | |
| Delete(ins); | |
| Delattr(c, "nested:outer"); | |
| } else { | |
| // global unnamed struct - ignore it and its instances | |
| SetFlag(c, "feature:ignore"); | |
| while (next && Getattr(next, "nested:unnamedtype") == c) { | |
| SetFlag(next, "feature:ignore"); | |
| next = nextSibling(next); | |
| } | |
| c = next; | |
| continue; | |
| } | |
| } else if (cparse_cplusplusout) { | |
| if (Getattr(c, "nested:outer")) { | |
| Node *ins = create_insert(c, true); | |
| insertNodeAfter(c, ins); | |
| Delete(ins); | |
| Delattr(c, "nested:outer"); | |
| } | |
| } | |
| // process children | |
| Swig_nested_name_unnamed_c_structs(c); | |
| c = next; | |
| } | |
| } | |
| static void remove_outer_class_reference(Node *n) { | |
| for (Node *c = firstChild(n); c; c = nextSibling(c)) { | |
| if (GetFlag(c, "feature:flatnested") || Language::instance()->nestedClassesSupport() == Language::NCS_None) { | |
| Delattr(c, "nested:outer"); | |
| remove_outer_class_reference(c); | |
| } | |
| } | |
| } | |
| void Swig_nested_process_classes(Node *n) { | |
| if (!n) | |
| return; | |
| Node *c = firstChild(n); | |
| while (c) { | |
| Node *next = nextSibling(c); | |
| if (!Getattr(c, "templatetype")) { | |
| if (GetFlag(c, "nested") && (GetFlag(c, "feature:flatnested") || Language::instance()->nestedClassesSupport() == Language::NCS_None)) { | |
| removeNode(c); | |
| if (!checkAttribute(c, "access", "public")) | |
| SetFlag(c, "feature:ignore"); | |
| else if (Strcmp(nodeType(n), "extend") == 0 && Strcmp(nodeType(parentNode(n)), "class") == 0) | |
| insertNodeAfter(parentNode(n), c); | |
| else | |
| insertNodeAfter(n, c); | |
| } | |
| Swig_nested_process_classes(c); | |
| } | |
| c = next; | |
| } | |
| remove_outer_class_reference(n); | |
| } |