void dump_stack(Context& ctx) { std::list<const TreeNode *>::reverse_iterator it(ctx.stack.rbegin()), itEnd(ctx.stack.rend()); printf("Current execution stack:\n"); int indent = 3; for(++it; it!=itEnd; ++it) { const TreeNode& tag = **it; printf("%*c%s(%d): processing <%s>\n", indent, ' ', tag.mpLocation->mName.c_str(), tag.mLineno, tag.mName.c_str()); indent += 3; } indent = 3; std::list<TreeNode *>::reverse_iterator it2(ctx.construction_stack.rbegin()), it2End(ctx.construction_stack.rend()); for(; it2!=it2End; ++it2) { const TreeNode& tag = **it2; printf("%*c%s(%d): while creating tag <%s>\n", indent, ' ', tag.mpLocation->mName.c_str(), tag.mLineno, tag.mName.c_str()); indent += 3; } indent = 3; for(it=ctx.invocation_stack.rbegin(), itEnd=ctx.invocation_stack.rend(); it!=itEnd; ++it) { const TreeNode& tag = **it; printf("%*c%s(%d): while invoked from tag <%s>\n", indent, ' ', tag.mpLocation->mName.c_str(), tag.mLineno, tag.mName.c_str()); indent += 3; } }
void HACD::CreateGraph() { // vertex to triangle adjacency information std::vector< std::set<long> > vertexToTriangles; vertexToTriangles.resize(m_nPoints); for(size_t t = 0; t < m_nTriangles; ++t) { vertexToTriangles[m_triangles[t].X()].insert(static_cast<long>(t)); vertexToTriangles[m_triangles[t].Y()].insert(static_cast<long>(t)); vertexToTriangles[m_triangles[t].Z()].insert(static_cast<long>(t)); } m_graph.Clear(); m_graph.Allocate(m_nTriangles, 5 * m_nTriangles); unsigned long long tr1[3]; unsigned long long tr2[3]; long i1, j1, k1, i2, j2, k2; long t1, t2; for (size_t v = 0; v < m_nPoints; v++) { std::set<long>::const_iterator it1(vertexToTriangles[v].begin()), itEnd(vertexToTriangles[v].end()); for(; it1 != itEnd; ++it1) { t1 = *it1; i1 = m_triangles[t1].X(); j1 = m_triangles[t1].Y(); k1 = m_triangles[t1].Z(); tr1[0] = GetEdgeIndex(i1, j1); tr1[1] = GetEdgeIndex(j1, k1); tr1[2] = GetEdgeIndex(k1, i1); std::set<long>::const_iterator it2(it1); for(++it2; it2 != itEnd; ++it2) { t2 = *it2; i2 = m_triangles[t2].X(); j2 = m_triangles[t2].Y(); k2 = m_triangles[t2].Z(); tr2[0] = GetEdgeIndex(i2, j2); tr2[1] = GetEdgeIndex(j2, k2); tr2[2] = GetEdgeIndex(k2, i2); int shared = 0; for(int i = 0; i < 3; ++i) { for(int j = 0; j < 3; ++j) { if (tr1[i] == tr2[j]) { shared++; } } } if (shared == 1) // two triangles are connected if they share exactly one edge { m_graph.AddEdge(t1, t2); } } } } if (m_ccConnectDist >= 0.0) { m_graph.ExtractCCs(); if (m_callBack) { char msg[1024]; sprintf(msg, "nCC %lu\n", static_cast<long unsigned int>(m_graph.m_nCCs)); (*m_callBack)(msg, 0.0, 0.0, m_graph.GetNVertices()); } if (m_graph.m_nCCs > 1) { std::vector< std::set<long> > cc2V; cc2V.resize(m_graph.m_nCCs); long cc; for(size_t t = 0; t < m_nTriangles; ++t) { cc = m_graph.m_vertices[t].m_cc; cc2V[cc].insert(m_triangles[t].X()); cc2V[cc].insert(m_triangles[t].Y()); cc2V[cc].insert(m_triangles[t].Z()); } for(size_t cc1 = 0; cc1 < m_graph.m_nCCs; ++cc1) { for(size_t cc2 = cc1+1; cc2 < m_graph.m_nCCs; ++cc2) { std::set<long>::const_iterator itV1(cc2V[cc1].begin()), itVEnd1(cc2V[cc1].end()); for(; itV1 != itVEnd1; ++itV1) { double distC1C2 = std::numeric_limits<double>::max(); double dist; t1 = -1; t2 = -1; std::set<long>::const_iterator itV2(cc2V[cc2].begin()), itVEnd2(cc2V[cc2].end()); for(; itV2 != itVEnd2; ++itV2) { dist = (m_points[*itV1] - m_points[*itV2]).GetNorm(); if (dist < distC1C2) { distC1C2 = dist; t1 = *vertexToTriangles[*itV1].begin(); std::set<long>::const_iterator it2(vertexToTriangles[*itV2].begin()), it2End(vertexToTriangles[*itV2].end()); t2 = -1; for(; it2 != it2End; ++it2) { if (*it2 != t1) { t2 = *it2; break; } } } } if (distC1C2 <= m_ccConnectDist && t1 >= 0 && t2 >= 0) { m_graph.AddEdge(t1, t2); } } } } } } }
void output_special_tag(Context& ctx, std::string *out, const TreeNode& tag) { if (tag.mName == "lina:fireball") { const TreeAttribute *a1 = tag.Attrib("src"); const TreeAttribute *a2 = tag.Attrib("dst"); if (!a1 || !a2) error(ctx, "<lina:fireball> requires SRC and DST attributes"); g_fileCopies[a2->mValue] = a1->mValue; } else if (tag.mName == "lina:write") { const TreeAttribute *a = tag.Attrib("file"); if (!a) error(ctx, "<lina:write> must specify FILE"); std::string s; std::list<TreeNode *> tempStack; ctx.construction_stack.swap(tempStack); int cdataCount = ctx.cdata_count; int preCount = ctx.pre_count; ctx.cdata_count = 0; ctx.pre_count = 0; bool bHoldingSpace = ctx.holding_space; bool bEatNextSpace = ctx.eat_next_space; ctx.holding_space = false; ctx.eat_next_space = true; output_tag_contents(ctx, &s, tag); ctx.holding_space = bHoldingSpace; ctx.eat_next_space = bEatNextSpace; ctx.pre_count = cdataCount; ctx.cdata_count = preCount; ctx.construction_stack.swap(tempStack); std::string filename(create_output_filename(a->mValue)); FILE *f = fopen(filename.c_str(), "wb"); if (!f) error(ctx, "couldn't create \"%s\"", a->mValue.c_str()); fwrite(s.data(), s.length(), 1, f); fclose(f); printf("created file: %s\n", a->mValue.c_str()); } else if (tag.mName == "lina:body") { // printf("outputting:\n"); // dump_parse_tree(*ctx.invocation_stack.back(), 4); output_tag_contents(ctx, out, *ctx.invocation_stack.back()); } else if (tag.mName == "lina:tag") { const TreeAttribute *a = tag.Attrib("name"); if (!a) error(ctx, "<lina:tag> must have NAME attribute"); ctx.construction_stack.push_back(ctx.mpDocument->AllocNode()); TreeNode *new_tag = ctx.construction_stack.back(); new_tag->mpLocation = tag.mpLocation; new_tag->mLineno = tag.mLineno; new_tag->mName = a->mValue; new_tag->mbIsText = false; new_tag->mbIsControl = false; // compatibility if (!new_tag->mName.compare(0, 2, "w:")) new_tag->mName.replace(0, 2, "lina:"); output_tag_contents(ctx, NULL, tag); ctx.construction_stack.pop_back(); output_tag(ctx, out, *new_tag); } else if (tag.mName == "lina:arg") { if (!out && ctx.construction_stack.empty()) error(ctx, "<lina:arg> can only be used in an output context"); const TreeAttribute *a = tag.Attrib("name"); if (!a) error(ctx, "<lina:arg> must have NAME attribute"); if (ctx.invocation_stack.empty()) error(ctx, "<lina:arg> can only be used during macro expansion"); std::list<const TreeNode *>::const_iterator it(ctx.invocation_stack.end()); --it; int levels = 1; const char *name = a->mValue.c_str(); while(*name == '^') { ++levels; ++name; if (it == ctx.invocation_stack.begin()) error(ctx, "Number of up-scope markers in name exceeds macro nesting level"); --it; } const TreeNode& macrotag = **it; const TreeAttribute *a2 = macrotag.Attrib(name); if (!a2) error(ctx, "macro invocation <%s> does not have an attribute \"%s\"", macrotag.mName.c_str(), name); if (out) { *out += a2->mValue; ctx.eat_next_space = false; ctx.holding_space = false; } else { TreeNode *t = ctx.mpDocument->AllocNode(); t->mpLocation = tag.mpLocation; t->mLineno = tag.mLineno; t->mbIsControl = false; t->mbIsText = true; t->mName = a2->mValue; ctx.construction_stack.back()->mChildren.push_back(t); } } else if (tag.mName == "lina:if-arg") { const TreeAttribute *a = tag.Attrib("name"); if (!a) error(ctx, "<lina:if-arg> must have NAME attribute"); if (ctx.invocation_stack.empty()) error(ctx, "<lina:if-arg> can only be used during macro expansion"); const TreeNode& macrotag = *ctx.invocation_stack.back(); const TreeAttribute *a2 = macrotag.Attrib(a->mValue); if (a2) output_tag_contents(ctx, out, tag); } else if (tag.mName == "lina:if-not-arg") { const TreeAttribute *a = tag.Attrib("name"); if (!a) error(ctx, "<lina:if-not-arg> must have NAME attribute"); if (ctx.invocation_stack.empty()) error(ctx, "<lina:if-not-arg> can only be used during macro expansion"); const TreeNode& macrotag = *ctx.invocation_stack.back(); const TreeAttribute *a2 = macrotag.Attrib(a->mValue); if (!a2) output_tag_contents(ctx, out, tag); } else if (tag.mName == "lina:attrib") { if (ctx.construction_stack.empty()) error(ctx, "<lina:attrib> can only be used in a <lina:tag> element"); const TreeAttribute *a = tag.Attrib("name"); if (!a) error(ctx, "<lina:attrib> must have NAME attribute"); std::string s; std::list<TreeNode *> tempStack; ctx.construction_stack.swap(tempStack); ++ctx.cdata_count; ++ctx.pre_count; bool bHoldingSpace = ctx.holding_space; bool bEatNextSpace = ctx.eat_next_space; ctx.holding_space = false; ctx.eat_next_space = true; output_tag_contents(ctx, &s, tag); ctx.holding_space = bHoldingSpace; ctx.eat_next_space = bEatNextSpace; --ctx.pre_count; --ctx.cdata_count; ctx.construction_stack.swap(tempStack); TreeNode *t = ctx.construction_stack.back(); TreeAttribute new_att; if (tag.Attrib("novalue")) { new_att.mbNoValue = true; } else { new_att.mbNoValue = false; new_att.mValue = s; } new_att.mName = a->mValue; t->mAttribs.push_back(new_att); } else if (tag.mName == "lina:pull") { if (ctx.invocation_stack.empty()) error(ctx, "<lina:pull> can only be used during macro expansion"); const TreeAttribute *a = tag.Attrib("name"); if (!a) error(ctx, "<lina:pull> must have NAME attribute"); const TreeNode *t = ctx.find_tag(a->mValue); if (!t) error(ctx, "cannot find tag <%s> referenced in <lina:pull>", a->mValue.c_str()); output_tag_contents(ctx, out, *t); } else if (tag.mName == "lina:for-each") { const TreeAttribute *a = tag.Attrib("name"); if (!a) error(ctx, "<lina:for-each> must have NAME attribute"); std::string node_name; const TreeNode *parent; if (ctx.invocation_stack.empty()) { if (!a->mValue.empty() && a->mValue[0] == '/') parent = ctx.mpDocument->mpRoot->ResolvePath(a->mValue.substr(1), node_name); else error(ctx, "path must be absolute if not in macro context"); } else { std::list<const TreeNode *>::reverse_iterator it(ctx.invocation_stack.rbegin()), itEnd(ctx.invocation_stack.rend()); for(; it!=itEnd; ++it) { parent = (*it)->ResolvePath(a->mValue, node_name); if(parent) break; if (!a->mValue.empty() && a->mValue[0] == '/') break; } } if (!parent) error(ctx, "cannot resolve path \"%s\"", a->mValue.c_str()); std::list<TreeNode *>::const_iterator it2(parent->mChildren.begin()), it2End(parent->mChildren.end()); ctx.invocation_stack.push_back(NULL); for(; it2!=it2End; ++it2) { if ((*it2)->mName == node_name) { ctx.invocation_stack.back() = *it2; output_tag_contents(ctx, out, tag); } } ctx.invocation_stack.pop_back(); } else if (tag.mName == "lina:apply") { const TreeAttribute *a = tag.Attrib("name"); if (!a) error(ctx, "<lina:apply> must have NAME attribute"); std::map<std::string, TreeNode *>::const_iterator it(ctx.mpDocument->mMacros.find(a->mValue)); if (it == ctx.mpDocument->mMacros.end()) error(ctx, "macro \"%s\" undeclared", a->mValue.c_str()); std::list<TreeNode *>::const_iterator it2(tag.mChildren.begin()), it2End(tag.mChildren.end()); ctx.invocation_stack.push_back(NULL); for(; it2!=it2End; ++it2) { if (!(*it2)->mbIsText) { ctx.invocation_stack.back() = *it2; output_tag_contents(ctx, out, *(*it).second); } } ctx.invocation_stack.pop_back(); } else if (tag.mName == "lina:if-present") { if (ctx.invocation_stack.empty()) error(ctx, "<lina:if-present> can only be used during macro expansion"); const TreeAttribute *a = tag.Attrib("name"); if (!a) error(ctx, "<lina:if-present> must have NAME attribute"); const TreeNode *t = ctx.find_tag(a->mValue); if (t) output_tag_contents(ctx, out, tag); } else if (tag.mName == "lina:if-not-present") { if (ctx.invocation_stack.empty()) error(ctx, "<lina:if-not-present> can only be used during macro expansion"); const TreeAttribute *a = tag.Attrib("name"); if (!a) error(ctx, "<lina:if-not-present> must have NAME attribute"); const TreeNode *t = ctx.find_tag(a->mValue); if (!t) output_tag_contents(ctx, out, tag); } else if (tag.mName == "lina:pre") { ++ctx.pre_count; ++ctx.cdata_count; if (!out) output_standard_tag(ctx, out, tag); else { output_tag_contents(ctx, out, tag); } --ctx.cdata_count; --ctx.pre_count; } else if (tag.mName == "lina:cdata") { ++ctx.cdata_count; if (!out) output_standard_tag(ctx, out, tag); else output_tag_contents(ctx, out, tag); --ctx.cdata_count; } else if (tag.mName == "lina:delay") { std::list<TreeNode *>::const_iterator it(tag.mChildren.begin()), itEnd(tag.mChildren.end()); for(; it!=itEnd; ++it) { output_standard_tag(ctx, out, **it); } } else if (tag.mName == "lina:dump-stack") { dump_stack(ctx); } else if (tag.mName == "lina:replace") { const TreeAttribute *a = tag.Attrib("from"); if (!a || a->mbNoValue) error(ctx, "<lina:replace> must have FROM attribute"); const TreeAttribute *a2 = tag.Attrib("to"); if (!a2 || a2->mbNoValue) error(ctx, "<lina:replace> must have TO attribute"); const std::string& x = a->mValue; const std::string& y = a2->mValue; std::string s, t; std::string::size_type i = 0; output_tag_contents(ctx, &s, tag); for(;;) { std::string::size_type j = s.find(x, i); if (j != i) t.append(s, i, j-i); if (j == std::string::npos) break; t.append(y); i = j + x.size(); } TreeNode *new_tag = ctx.mpDocument->AllocNode(); new_tag->mpLocation = tag.mpLocation; new_tag->mLineno = tag.mLineno; new_tag->mbIsText = true; new_tag->mbIsControl = false; new_tag->mName = t; output_tag(ctx, out, *new_tag); } else if (tag.mName == "lina:set-option") { const TreeAttribute *a_name = tag.Attrib("name"); if (!a_name) error(ctx, "<lina:set-option> must have NAME attribute"); if (a_name->mValue == "link-truncate") { const TreeAttribute *a_val = tag.Attrib("baseurl"); if (!a_val || a_val->mbNoValue) error(ctx, "option \"link-truncate\" requires BASEURL attribute"); bool bTruncate = !tag.Attrib("notruncate"); g_truncateURLs.push_back(std::make_pair(a_val->mValue, bTruncate)); } else if (a_name->mValue == "output-dir") { const TreeAttribute *a_val = tag.Attrib("target"); if (!a_val || a_val->mbNoValue) error(ctx, "option \"output-dir\" requires TARGET attribute"); g_outputDir = a_val->mValue; } else if (a_name->mValue == "tag-info") { const TreeAttribute *a_tagname = tag.Attrib("tag"); if (!a_tagname || a_tagname->mbNoValue) error(ctx, "option \"tag-info\" requires TAG attribute"); const TreeAttribute *a_cdata = tag.Attrib("cdata"); if (!a_cdata || a_cdata->mbNoValue) error(ctx, "option \"tag-info\" requires CDATA attribute"); TreeNode::SetSupportsCDATA(a_tagname->mValue, is_true(a_cdata->mValue)); } else error(ctx, "option \"%s\" unknown\n", a_name->mValue.c_str()); } else if (tag.mName == "lina:data") { // do nothing } else if (tag.mName == "lina:source") { if (out) { std::list<TreeNode *>::const_iterator itBegin(tag.mChildren.begin()), it(itBegin), itEnd(tag.mChildren.end()); for(; it!=itEnd; ++it) { output_source_tags(ctx, out, **it); } } } else if (tag.mName == "lina:htmlhelp-toc") { const TreeAttribute *a_val = tag.Attrib("file"); if (!a_val || a_val->mbNoValue) error(ctx, "<lina:htmlhelp-toc> requires FILE attribute"); const std::string filename(create_output_filename(a_val->mValue)); // build new tag with TOC contents ctx.construction_stack.push_back(ctx.mpDocument->AllocNode()); TreeNode *new_tag = ctx.construction_stack.back(); new_tag->mpLocation = tag.mpLocation; new_tag->mLineno = tag.mLineno; new_tag->mName = a_val->mValue; new_tag->mbIsText = false; new_tag->mbIsControl = false; output_tag_contents(ctx, NULL, tag); ctx.construction_stack.pop_back(); output_tag(ctx, out, *new_tag); FILE *f = fopen(filename.c_str(), "wb"); if (!f) error(ctx, "couldn't create htmlhelp toc \"%s\"", a_val->mValue.c_str()); output_toc(f, *new_tag); fclose(f); } else if (tag.mName == "lina:htmlhelp-project") { const TreeAttribute *file_val = tag.Attrib("file"); if (!file_val || file_val->mbNoValue) error(ctx, "<lina:htmlhelp-project> requires FILE attribute"); const TreeAttribute *output_val = tag.Attrib("output"); if (!output_val || output_val->mbNoValue) error(ctx, "<lina:htmlhelp-project> requires OUTPUT attribute"); const TreeAttribute *toc_val = tag.Attrib("toc"); if (!toc_val || toc_val->mbNoValue) error(ctx, "<lina:htmlhelp-project> requires TOC attribute"); const TreeAttribute *title_val = tag.Attrib("title"); if (!title_val || title_val->mbNoValue) error(ctx, "<lina:htmlhelp-project> requires TITLE attribute"); const std::string filename(create_output_filename(file_val->mValue)); FILE *f = fopen(filename.c_str(), "wb"); if (!f) error(ctx, "couldn't create htmlhelp project \"%s\"", file_val->mValue.c_str()); fprintf(f, "[OPTIONS]\n" "Auto Index=Yes\n" "Compatibility=1.1 or later\n" "Compiled file=%s\n" "Contents file=%s\n" "Default topic=index.html\n" "Display compile progress=no\n" "Full-text search=Yes\n" , output_val->mValue.c_str() , toc_val->mValue.c_str() ); const TreeAttribute *fullstop_val = tag.Attrib("fullstop"); if (fullstop_val && !fullstop_val->mbNoValue) fprintf(f, "Full text search stop list file=%s\n", fullstop_val->mValue.c_str()); fprintf(f, "Language=0x0409 English (United States)\n" "Title=%s\n" "\n" "[FILES]\n" , title_val->mValue.c_str() ); std::list<std::string>::const_iterator it(g_htmlHelpFiles.begin()), itEnd(g_htmlHelpFiles.end()); for(; it!=itEnd; ++it) { fprintf(f, "%s\n", (*it).c_str()); } fclose(f); } else if (tag.mName == "lina:htmlhelp-addfile") { const TreeAttribute *file_val = tag.Attrib("file"); if (!file_val || file_val->mbNoValue) error(ctx, "<lina:htmlhelp-addfile> requires FILE attribute"); g_htmlHelpFiles.push_back(file_val->mValue); } else { std::string macroName(tag.mName, 5, std::string::npos); std::map<std::string, TreeNode *>::const_iterator it = ctx.mpDocument->mMacros.find(macroName); if (it == ctx.mpDocument->mMacros.end()) error(ctx, "macro <lina:%s> not found", macroName.c_str()); // dump_stack(ctx); // printf("executing macro: %s (%s:%d)\n", tag.mName.c_str(), tag.mLocation->name.c_str(), tag.mLineno); ctx.invocation_stack.push_back(&tag); output_tag_contents(ctx, out, *(*it).second); ctx.invocation_stack.pop_back(); // printf("exiting macro: %s (%s:%d)\n", tag.mName.c_str(), tag.mLocation->name.c_str(), tag.mLineno); } }