#include "www.h" #include #include #define IMAGECLASS WWW #define IMAGEFILE #include #define TFILE #include #define LLOG(x) // LOG(x) String targetdir = GetHomeDirFile("www2"); String rootdir = GetHomeDirFile("upp.stable"); String masterdir = GetHomeDirFile("upp.src"); String uppbox = masterdir + "/uppbox"; String uppsrc = rootdir + "/uppsrc"; //String devsrc = devdir + "/uppsrc"; String reference = rootdir + "/reference"; String examples = rootdir + "/examples"; String webtopic = "topic://uppweb"; VectorMap escape; ArrayMap tt; Vector ttId; Vector ttFullIds; VectorMap links; VectorMap labels; Htmls header, lastUpdate; Array bar; Array languages; typedef Image (*ImageFn)(); Index il; namespace Upp { struct TopicData__ : Moveable { String title; const byte *data; int len; }; VectorMap > >& Topics__(); }; void ClearGlobals() { reflink.Clear(); escape.Clear(); tt.Clear(); ttId.Clear(); ttFullIds.Clear(); links.Clear(); labels.Clear(); bar.Clear(); languages.Clear(); il.Clear(); } String GetRcFile(const char *s) { String f = GetDataFile(s); if(FileExists(f)) return f; return GetHomeDirFile("upp.src/uppbox/uppweb/" + AsString(s)); } bool ContainsAt(const String &source, const String &pattern, int pos) { return pos >= 0 && pos + pattern.GetLength() <= source.GetLength() && 0 == memcmp(source.Begin() + pos, pattern.Begin(), pattern.GetLength()); } bool StartsWith(const String &source, const String &pattern) { return ContainsAt(source, pattern, 0); } bool EndsWith(const String &source, const String &pattern) { return ContainsAt(source, pattern, source.GetLength() - pattern.GetLength()); } String ImgName(int q) { return Sprintf("%di.png", q); } typedef Image (*ImageFn)(); namespace Upp { template<> hash_t GetHashValue(const ::ImageFn& fn) { return (unsigned)(uintptr_t) fn; } }; String GetImageSrc(ImageFn img) { int q = il.Find(img); if(il.Find(img) < 0) { q = il.GetCount(); il.Add(img); PNGEncoder png; png.SaveFile(AppendFileName(targetdir, ImgName(q)),(*img)()); } return ImgName(q); } Htmls Wimg(ImageFn img) { return HtmlImg(GetImageSrc(img)).Border(0); } Htmls RoundFrame(Htmls data, String border, Color bg) { return HtmlPackedTable().BgColor(bg).Width(-100) .Attr("style", "border-style: solid; border-width: 1px; border-color: #" + border + ";") / HtmlLine() / data; } HtmlTag BoxWidth(int width) { return HtmlPackedTable().Width(width) / HtmlLine(); } Htmls BarSection(const char *txt) { Htmls bar; bar.Br(); bar << HtmlPackedTable().BgColor(WhiteGray).Width(-100) / (HtmlRow() / ( HtmlCell().Width(10) / " " + HtmlCell() / HtmlArial(8) / HtmlBold() / txt + HtmlCell().Width(10) / " " )); return bar; } Htmls BarCaption(const char *text) { return HtmlLine() .Width(-100) .VCenter() .Style("background-image: url('" + GetImageSrc(WWW::Caption) + "'); " "border: 0px solid black;" "padding-left:12px; padding-right:0px; " "padding-top:1px; padding-bottom:1px;" "color:#FFFFFF;") / HtmlBold() / HtmlArial(8) / text; } Htmls BarCaptionLang(const char *text) { return HtmlLine() .Width(20) .VCenter() .Style("background-image: url('" + GetImageSrc(WWW::News2) + "'); " "border: 0px solid black;" "padding-left:12px; padding-right:0px; " "padding-top:1px; padding-bottom:1px;" "color:#FFFFFF;") / HtmlBold() / HtmlArial(8) / text; } Htmls BarItem(Htmls content, const char *style) { String bgStyle = "background-image: url('" + GetImageSrc(WWW::Button) + "'); "; return HtmlLine().Width(-100).VCenter().Style(bgStyle + style) / content; } Htmls BarLink(const char *link, const char *text, bool nxt = true) { String style = "border: 0px solid black; " "padding-left:12px; padding-right:0px; " "padding-top:6px; padding-bottom:6px;"; if(nxt) style += " border-top: 1px solid #6E89AE;"; return BarItem( HtmlLink(link).Class("l1") / text, style ); } Htmls SearchBar(const char *domain) { Htmls form = HtmlForm("https://www.google.com/search", false, "GET") .Style("margin:0px;padding:0px;") / ( HtmlHidden("ie", "UTF-8") + HtmlHidden("oe", "UTF-8") + ~HtmlEdit("q", 15).Attr("placeholder", t_("Site search")) + ~HtmlHidden("sitesearch", domain) ); Htmls content; content << HtmlPackedTable().Width(-100) / HtmlRow() / ( HtmlCell() / Wimg(WWW::google) + HtmlCell() / form ); String style = "border: 0px solid black; " "padding-left:6px; padding-right:0px; " "padding-top:4px; padding-bottom:4px;" "border-top: 1px solid #6E89AE;"; return BarItem(content, style); } HtmlTag HtmlPadding(int p) { return HtmlPackedTable().Width(-100) / HtmlLine(); } String QtfAsHtml(const char *qtf, Index& css, const VectorMap& links, const VectorMap& labels, const String& outdir, const String& fn = Null) { return EncodeHtml(ParseQTF(qtf), css, links, labels, outdir, fn, Zoom(8, 40), escape, 40); } String GetText(const char *s) { return GetTopic(s).text; } String ChangeTopicLanguage(const String &topic, int lang) { int pos = topic.ReverseFind('$'); if (pos < 0) return ""; String langtxt = ToLower(LNGAsText(lang)); return topic.Left(pos+1) + langtxt + topic.Mid(pos+1+langtxt.GetCount()); } String GetTopicLanguage(const String &topic) { int pos = topic.ReverseFind('$'); if (pos < 0) return ""; return topic.Mid(pos+1, 5); } String FormatDateRFC822(const Time& t) { int tz = int((GetSysTime()-GetUtcTime())/60); return Format("%s, %d %Mon %d %02d:%02d:%02d %s%04d", DayName(DayOfWeek(t)).Left(3), t.day,t.month,t.year, t.hour,t.minute,t.second, tz>0?"+":"",tz/60*100+(tz+1440)%60); } String Www(const char *topic, int lang, String topicLocation = webtopic + "/www/") { String strLang = ToLower(LNGAsText(lang)); String www = GatherTopics(tt, ttFullIds, String().Cat() << topicLocation << topic << "$" << strLang, "", false); if (www != "index.html") return www; return GatherTopics(tt, ttFullIds, String().Cat() << topicLocation << topic << "$" << "en-us", "", false); } struct Title { String title, link; Title(String title, String link) : title(TrimBoth(title)), link(link) {}; bool operator < (const Title& other) const { const char *val = title.Begin(); const char *valOther = other.title.Begin(); for(;; val++, valOther++) { String str, strOther; str.Clear(); strOther.Clear(); for (; *val != '\0' && *val != '.' && *val != ' '; ++val) str.Cat(*val); for (; *valOther != '\0' && *valOther != '.' && *valOther != ' '; ++valOther) strOther.Cat(*valOther); int num = ScanInt(str); int numOther = ScanInt(strOther); if (IsNull(num) && IsNull(numOther)) return str < strOther; if (IsNull(num)) return true; if (IsNull(numOther)) return false; if (num != numOther) return num < numOther; } return title < other.title; } }; String FolderLinks(String package, String group, int lang, int level, String parentIds) { String qtf; Array titles; FindFile ff(AppendFileName(AppendFileName(AppendFileName(uppsrc, package), group + ".tpp"), "*.tpp")); while(ff) { if(ff.IsFile()) { if (ff.GetName().Find("en-us") >= 0) { String title; String tl = "topic://" + package + '/' + group + '/' + GetFileTitle(ff.GetName()); GatherTopics(tt, ttFullIds, tl, title, parentIds, false); titles.Add(Title(DeQtf(Nvl(title, tl)), tl)); //qtf << "________[^" << tl << "^ " << DeQtf(Nvl(title, tl)) << "]&"; } } ff.Next(); } Sort(titles); for (int i = 0; i < titles.GetCount(); ++i) qtf << "________[^" << titles[i].link << "^ " << titles[i].title << "]&"; return qtf; } void AddFiles(String& qtf, const String& dir, const char* ext, bool& b) { FindFile ff(AppendFileName(dir, "*." + String(ext))); while(ff) { qtf << "[A4* " << DeQtf(ff.GetName()) << "]&&" << CppAsQtf(LoadFile(AppendFileName(dir, ff.GetName()))) << "&&&"; ff.Next(); b = true; } } struct Isort { bool operator()(const String& a, const String& b) const { return ToUpper(a) < ToUpper(b); } }; String MakeExamples(const char *dir, const char *www, int language, String parentIds) { String ttxt; FindFile ff(AppendFileName(dir, "*.*")); ttxt << "{{1:3 "; bool next = false; Vector<String> ls; while(ff) { if(ff.IsFolder()) ls.Add(ff.GetName()); ff.Next(); } Sort(ls, Isort()); for(int i = 0; i < ls.GetCount(); i++) { String name = ls[i]; String link = String().Cat() << www << '$' << name << "$" << ToLower(LNGAsText(language)) << ".html"; Topic& topic = tt.Add(link); topic.title = name; int q = tt.GetCount() - 1; String fullIds = parentIds + "/" + FormatInt(q); ttFullIds.Add(fullIds); String fn = AppendFileName( AppendFileName( AppendFileName(uppbox, "uppweb"), String(www) + ".tpp" ), topic.title + "_" + ToLower(LNGAsText(language)) + ".tpp" ); String h = ReadTopic(LoadFile(fn)).text; Package p; p.Load(AppendFileName(AppendFileName(dir, name), name + ".upp")); topic.text << "[R6* " << name << "]&&" << DeQtf(p.description) << "&"; if(h.GetCount()) topic.text << h; topic.text << "[A2<l0r0 &&"; String d = AppendFileName(dir, name); bool b = false; AddFiles(topic.text, d, "h", b); AddFiles(topic.text, d, "hpp", b); AddFiles(topic.text, d, "cpp", b); AddFiles(topic.text, d, "icpp", b); AddFiles(topic.text, d, "java", b); AddFiles(topic.text, d, "witz", b); AddFiles(topic.text, d, "usc", b); AddFiles(topic.text, d, "lay", b); AddFiles(topic.text, d, "key", b); AddFiles(topic.text, d, "brc", b); AddFiles(topic.text, d, "sch", b); AddFiles(topic.text, d, "xml", b); if(b) { if(next) ttxt << "\n::^ "; ttxt << "[^" << link << "^* " << DeQtf(topic.title) << "]::^ " << DeQtf(p.description); next = true; } } ttxt << "}}&&"; return ttxt; } class HeaderNumber { public: HeaderNumber(const String& prefix = {}) : m_prefix(prefix) { } bool IsFirst() const { return m_number == 1; } int GetNumber() const { return m_number; } String GenNext() { return m_prefix + IntStr(m_number++); } private: String m_prefix; int m_number = 1; }; class PackageDocsGenerator final { public: PackageDocsGenerator() : m_hnumber("4.") {} const Vector<String>& GetHeaders() { return m_headers; } void Generate(Index<String>& x, String& qtf, const char* folder, int lang, int level, String parent) { if(x.Find(folder) >= 0) return; x.Add(folder); String srcdoc = FolderLinks(folder, "srcdoc", lang, level, parent); String src = FolderLinks(folder, "src", lang, level, parent); Package p; p.Load(AppendFileName(uppsrc, AppendFileName(folder, GetFileName(folder) + ".upp"))); if(srcdoc.GetLength() || src.GetLength()) { bool first = m_hnumber.IsFirst(); String ref = ":4`_" + IntStr(m_hnumber.GetNumber()) + ":"; m_headers.Add(m_hnumber.GenNext() + " " + folder); qtf << (first ? "" : "[s0; &&]\n") << "[s19;" << ref << " " << m_headers.Top() << " 📦&]"; if(!IsNull(p.description)) qtf << "[2 " << p.description << "&]"; if(srcdoc.GetCount()) { qtf << "&[3/* " + Format(t_("Using %s"), folder) << "&]"; qtf << srcdoc; } if(src.GetCount()) { qtf << "&[3/* " << Format(t_("%s reference"), folder) << "&]"; qtf << src; } qtf << "\n"; } } private: HeaderNumber m_hnumber; Vector<String> m_headers; }; int CharFilterLbl(int c) { return IsAlNum(c) ? c : '.'; } void QtfAsPdf(PdfDraw &pdf, const char *qtf) { RichText txt = ParseQTF(qtf); Size page = Size(3968, 6074); UPP::Print(pdf, txt, page); } int GetLinkLanguage(const String &link) { int pos = link.ReverseFind('$'); if (pos < 0) return 0; int lang = LNGFromText(ToUpper(link.Mid(pos+1))); for (int i = 0; i < languages.GetCount(); ++i) { if (languages[i] == lang) return i; } return 0; } String TrimDescription(String description) { description.Replace("\"", ""); description.Replace(":", "."); constexpr int DESCRIPTION_SIZE_LIMIT = 158; if (description.GetLength() <= DESCRIPTION_SIZE_LIMIT) { return description; } description.Trim(DESCRIPTION_SIZE_LIMIT); int trim_idx = -1; for (int i = description.GetCount() - 1; i >= 0; i--) { if (description[i] != '.' && description[i] != '?') { continue; } trim_idx = i + 1; break; } if (trim_idx == -1 || trim_idx == 0) { return description; } description.Trim(trim_idx); return description; } String FindPageDescription(const RichText& qtf) { String description; Uuid style_id = qtf.GetStyleId("text"); if (!style_id.IsNullInstance()) { RichStyle style = qtf.GetStyle(style_id); for (int i = 0; i < qtf.GetPartCount(); i++) { if (!qtf.IsPara(i)) { continue; } RichPara para = qtf.Get(i); if (style_id == qtf.GetParaStyle(i)) { description = para.GetText().ToString(); break; } } } return TrimDescription(description); } #if 0 String AdSense3() { #ifdef _DEBUG return Null; #else return LoadFile(GetRcFile("adsense3.txt")); #endif } String AdSense2() { #ifdef _DEBUG return Null; #else return LoadFile(GetRcFile("adsense2.txt")); #endif } String AdSense() { #ifdef _DEBUG return Null; #else return LoadFile(GetRcFile("adsense.txt")); #endif } String AdLinks() { #ifdef _DEBUG return Null; #else return LoadFile(GetRcFile("adlinks.txt")); #endif } #endif void ExportPage(int i) { Index<String> css; String path = links.GetKey(i); RLOG("Exporting " << path); int ilang = GetLinkLanguage(path); SetLanguage(languages[ilang]); String text = GetText(path); RichText qtf = ParseQTF(tt[i].text); int h = qtf.GetHeight(1000); String qtflangs; String strlang; String jslang; Array <String> arrLangs; for (int il = 0; il < languages.GetCount(); ++il) { String topic = ChangeTopicLanguage(path, languages[il]); int itopic; if ((itopic = tt.Find(topic)) >= 0) { if (tt[itopic].title.Find(" (translated)") < 0) { if (il != ilang) { if (!strlang.IsEmpty()) strlang << ", "; arrLangs.Add("[^" + links[itopic] + "^ [2 " + ToLower(GetNativeLangName(languages[il])) + "]]"); } jslang+="'"+ links[itopic] +"':'" + GetNativeLangName(languages[il]) + "',"; } } } if(!jslang.IsEmpty()) jslang.Trim(jslang.GetCount()-1); if (arrLangs.GetCount() > 0) { for (int i = 0; i < arrLangs.GetCount(); ++i) { if (i == arrLangs.GetCount()-1 && i != 0) strlang << String(" ") + t_("and") + " "; else if (i > 0) strlang << ", "; strlang << arrLangs[i]; } } if (tt[i].title.Find("How to contribute. Web page") < 0) { String help = webtopic + "/www/contribweb$" + ToLower(LNGAsText(languages[ilang])); qtflangs += " " + String("[^") + help + "^ [<A2 " + t_("Do you want to contribute?") + "]]"; } String langs = QtfAsHtml(qtflangs, css, links, labels, targetdir, links[i]); String page = tt[i]; Array<String> htmlrep; int posB = 0; while (true) { posB = page.Find("[IHTMLTEXT", posB); if (posB < 0) break; int posBB = posB + (int)strlen("[IHTMLTEXT"); int pos0 = page.ReverseFind("[", posB-1); int posE = page.Find(";2", posBB); String html0 = page.Mid(posBB, posE - posBB); html0.Replace("`", ""); htmlrep.Add(html0); int posEE = page.Find("]&]", posE) + (int)strlen("]&]"); page = page.Left(pos0) + "QTFHTMLTEXT" + FormatInt(htmlrep.GetCount()-1) + page.Mid(posEE+1); } page = QtfAsHtml(page, css, links, labels, targetdir, links[i]); for (int iHtml = 0; iHtml < htmlrep.GetCount(); ++iHtml) page.Replace(String("QTFHTMLTEXT") + FormatInt(iHtml), htmlrep[iHtml]); #if 0 if(path == webtopic + "/www/download$en-us") page << AdSense3(); #endif Color bg = Color(210, 217, 210); Htmls footer; footer << HtmlTable().Border(0).Width(-100) / HtmlLine() + ~RoundFrame(HtmlPadding(8) / langs , "6E89AE;padding: 10px;", White); Htmls html; html << HtmlPackedTable().Width(-100) / HtmlLine().ColSpan(3) / header + HtmlPackedTable().Width(-100) / ( HtmlLine().ColSpan(3).BgColor(bg).Height(6) / "" + HtmlRow() / ( HtmlTCell().Center() / BoxWidth(160).Center() / ( bar[GetLinkLanguage(path)] + "<br>" + LoadFile(GetRcFile("facebook.txt")) + "<br><br>" + // "<p align=\"center\">" + #if 0 AdSense2() + "<br><br>" + AdLinks() + (h > 25000 ? "<br><br>" + AdSense2() : "") + #endif "<br><br><br>" + "<br><br><br>" + ~(HtmlLink("https://sourceforge.net/projects/upp/") / HtmlImg("https://sourceforge.net/sflogo.php?group_id=93970&type=2", "SourceForge.net Logo").Border(0).Width(125).Height(37)) + "<br><br>" + ~(HtmlLink("https://flathub.org/en/apps/org.ultimatepp.TheIDE") / HtmlImg(GetImageSrc(WWW::Flathub), "SourceForge.net Logo").Border(0).Width(125).Height(37)) + "<br><br>" + "<div style=\"background-color:#ffffff;width:125;height:35\">" + ~(HtmlLink("https://github.com/ultimatepp") / HtmlImg(GetImageSrc(WWW::GitHub), "GitHub Logo").Border(0).Width(125).Height(35)) + "</div>" + "<br>" + "<div style=\"background-color:#ffffff;width:125;height:35\">" + "<div style=\"height:5\"></div>" + ~(HtmlLink("https://discord.gg/8XzqQzXZzb") / HtmlImg("https://assets-global.website-files.com/6257adef93867e50d84d30e2/636e0b5061df29d55a92d945_full_logo_blurple_RGB.svg", "Discord Logo").Border(0).Width(125).Height(25)) + "</div>" + "<br>" + (links[i] == "index.html" ? lastUpdate : Htmls()) ) + HtmlTCell().BgColor(bg) / BoxWidth(6) / "" + HtmlTCell().Width(-100).BgColor(bg) / ( RoundFrame(HtmlPadding(8) / page , "6E89AE;padding: 10px;", White) + footer ) ) ) + Htmls("<script type=\"text/javascript\">var a={"+jslang+"};" "var p=window.location.pathname.split(\"/\");p=p[p.length-1];" "var s='<select id=\"lang\" onchange=\"window.location=document.getElementById(\\'lang\\').value;\">';" "for(l in a){if(p==l){d=\" selected=1\"}else{d=\"\"}s+='<option value=\"'+l+'\"'+d+'>'+a[l]+'</option>'}" "s+='</select>';" "var d=document.createElement('div');d.innerHTML=s;" "var c=document.getElementById('langs');c.replaceChild(d,c.firstChild);" "document.getElementById('langbox').style.display='block';</script>"); String topicTitle = tt.GetKey(i); String pageTitle = tt[i].title; if(IsNull(pageTitle)) pageTitle = "U++"; else if(StartsWith(topicTitle, "examples")) pageTitle = "Demos / " + pageTitle; else if(StartsWith(topicTitle, "reference")) pageTitle = "Examples / " + pageTitle; bool is_index = path == webtopic + "/www/index$en-us"; if(pageTitle != "U++" && !is_index) pageTitle << " :: U++"; auto htmlHeader = HtmlHeader() .Title(pageTitle) .Description(FindPageDescription(qtf)) .Css(AsCss(css) + "a.l1 { text-decoration:none; font-size: 8pt; font-family: sans-serif; " "font-weight: normal; }\n" "a.l1:link { color:#000000; }\n" "a.l1:visited { color:#000080; }\n" "a.l1:hover { color:#9933CC; }\n" "a.l1:active { color:#000000; }\n" "a.l2 { text-decoration:none; font-size: 12pt; font-family: sans-serif; " "font-variant: small-caps; }\n" "a.l2:link { color:#0066FF; }\n" "a.l2:visited { color:#FF6600; }\n" "a.l2:hover { color:#BC0624; }\n" "a.l2:active { color:#BC0024; }\n") .Other( "<META NAME=\"keywords\" " "CONTENT=\"" "framework, toolkit, widget, c++, visual, studio, dev-cpp, builder, ide, class, component," "wxwidgets, qt, rapid, application, development, rad, mfc, linux, macos, gui, sdl, directx, desktop" "\">" "<META name=\"robots\" content=\"index,follow\">\n" "<LINK rel=\"alternate\" type=\"application/rss+xml\" title=\"SVN changes\" href=\"svnchanges.xml\">\n" "<LINK rel=\"shortcut icon\" type=\"image/png\" href=\"favicon.png\">\n") .Create(); Htmls content = //"<!DOCTYPE html>" + "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n" + htmlHeader .BgColor(bg) .Alink(Red).Link(Black).Vlink(Blue) / html; if(!SaveFile(AppendFileName(targetdir, links[i]), content)) { RLOG("SaveFile failed!"); abort(); } RLOG("Exported page " << AppendFileName(targetdir, links[i])); } struct DownloadItem { Time tm; String fn; String path; int64 len; }; String Downloads() { String r; r << "{{1:2:2^@L " "Date:: " "[^app$ide$install_win32_en-us.html^ U`+`+ for Windows (with CLANG)]:: " "[^app$ide$install_posix_en-us.html^ U`+`+ for Linux/MacOS/BSD/Solaris]"; FindFile ff(AppendFileName(targetdir, "downloads/*.*")); SortedArrayMap<Date, Array<DownloadItem>> downs; while(ff) { if(ff.IsFile()) { DownloadItem down; down.tm = ff.GetLastWriteTime(); down.fn = ff.GetName(); down.path = ff.GetPath(); down.len = ff.GetLength(); Date date = down.tm; downs.GetAdd(date).Add(down); } ff.Next(); } auto FindDown = [](Array<DownloadItem>& a, const char* arch) -> String { String r; for(int i = 0; i < a.GetCount(); i++) { if(a[i].fn.Find(arch) >= 0) { r << FormatTime(a[i].tm, "hh:mm") << " [^downloads/" << a[i].fn << "^ \1" << a[i].fn << "\1]" << " (" << (a[i].len >> 20) << " MB)"; break; } } return r; }; Date d = GetSysDate(); for(int i = 0; i < 14; i++, d--) { Array<DownloadItem>& a = downs.GetAdd(d); r << "::@W " << FormatDate(d, "YYYY-MM-DD") << ":: " << FindDown(a, "win") << ":: " << FindDown(a, "posix"); } r << "}}"; for(int i = 14; i < downs.GetCount(); i++) { if(downs.GetKey(i) < d) for(int j = 0; j < downs[i].GetCount(); j++) DeleteFile(downs[i][j].path); } return r; } CONSOLE_APP_MAIN { StdLogSetup(LOG_COUT|LOG_FILE); RLOG("--- uppweb started at " << GetSysTime()); bool isdev = false; if(CommandLine().GetCount() && CommandLine()[0] == "dev") { isdev = true; rootdir = masterdir; targetdir << "/dev"; } uppsrc = AppendFileName(rootdir, "uppsrc"); RealizeDirectory(targetdir); RLOG("RootDir: " << rootdir); RLOG("TargetDir: " << targetdir); String downloads = Downloads(); FindFile ff(AppendFileName(targetdir, "*.*")); while(ff) { if(ff.IsFile()) FileDelete(ff.GetPath()); ff.Next(); } if (!DirectoryExists(rootdir)) { Cout() << ("Directory " + DeQtf(rootdir) + " does not exist\n"); return; } uppbox = AppendFileName(rootdir, "uppbox"); reference = AppendFileName(rootdir, "reference"); examples = AppendFileName(rootdir, "examples"); InitWwwTpp(); languages.Add(LNG_('E','N','U','S')); // en-us has to be the first one RealizeDirectory(targetdir); RLOG("Gather ref links " << uppsrc); GatherRefLinks(uppsrc, false); SaveFile(AppendFileName(targetdir, "sdj.gif"), LoadFile(GetRcFile("sdj.gif"))); #ifdef bmGIT_REVCOUNT auto version = AsString(atoi(bmGIT_REVCOUNT) + 2270); escape.Add("LATESTGIT", version); #endif String release = "17810"; escape.Add("RELEASE", release); escape.Add("RELEASET", release); escape.Add("UPDATETIME", Format("%`", GetUtcTime())); escape.Add("PAYPAL", LoadFile(GetRcFile("donations.txt"))); header = HtmlPackedTable() .Width(-100) .BgColor(White) .Attr("style", "border: 1px solid #6E89AE;" "padding-left: 10px;padding-right: 0px;padding-top: 0px;padding-bottom: 0px;") / HtmlRow() / ( HtmlCell() / HtmlLink("index.html") / Wimg(WWW::Logo6) + HtmlCell().Right().Bottom() .Style("padding-bottom: 5px; " "background-image: url('" + GetImageSrc(WWW::HB) + "')") / HtmlArial(14) / (/*AdSense() + "  " + */(isdev ? "<br>development version (master branch)" : "")) ); bar.SetCount(languages.GetCount()); int currentLang = GetCurrentLanguage(); for (int i = 0; i < languages.GetCount(); ++i) { Cout() << "Language " << LNGAsText(languages[i]); Htmls bi, bex, bdoc, bcom, bcon, bsearch, blang; int lang = languages[i]; SetLanguage(lang); Www("index", lang); Www("contribweb", lang); // bi << BarLink("index.html", "Home", false); bi << BarLink(Www("overview", lang), t_("Overview"), false); bi << BarLink(Www("examples", lang), t_("Examples")); { IGNORE_RESULT(Www("reference", lang)); int ri = tt.Find(webtopic + "/www/reference$" + ToLower(LNGAsText(lang))); int di = tt.Find(webtopic + "/www/examples$" + ToLower(LNGAsText(lang))); tt[di].text << MakeExamples(examples, "examples", lang, String("/") + FormatInt(di)); tt[di].text << tt[ri].text << '\n'; tt[di].text << MakeExamples(reference, "reference", lang, String("/") + FormatInt(di)); } bi << BarLink(Www("ss", lang), t_("Screenshots")); bi << BarLink(Www("comparison", lang), t_("Comparisons")); bi << BarLink(Www("apps", lang), t_("Applications")); bi << BarLink(Www("download", lang), t_("Download")); bi << BarLink(Www("documentation", lang), t_("Documentation")); { int di = tt.Find(webtopic + "/www/documentation$" + ToLower(LNGAsText(lang))); if (di >= 0) { Index<String> x; x.Clear(); String qtf; PackageDocsGenerator dgen; dgen.Generate(x, qtf, "Core", lang, 2, String("/") + FormatInt(di) + "/[Core]"); dgen.Generate(x, qtf, "Core/POP3", lang, 2, String("/") + FormatInt(di) + "/[Core/POP3]"); dgen.Generate(x, qtf, "Core/SMTP", lang, 2, String("/") + FormatInt(di) + "/[Core/SMTP]"); dgen.Generate(x, qtf, "Core/SSH", lang, 2, String("/") + FormatInt(di) + "/[Core/SSH]"); dgen.Generate(x, qtf, "Draw", lang, 2, String("/") + FormatInt(di) + "/[Draw]"); dgen.Generate(x, qtf, "CtrlCore", lang, 2, String("/") + FormatInt(di) + "/[CtrlCore]"); dgen.Generate(x, qtf, "CtrlLib", lang, 2, String("/") + FormatInt(di) + "/[CtrlLib]"); dgen.Generate(x, qtf, "RichText", lang, 2, String("/") + FormatInt(di) + "/[RichText]"); dgen.Generate(x, qtf, "RichEdit", lang, 2, String("/") + FormatInt(di) + "/[RichEdit]"); dgen.Generate(x, qtf, "Sql", lang, 2, String("/") + FormatInt(di) + "/[Sql]"); String d = AppendFileName(uppsrc, "*.*"); String p; for(int pass = 0; pass < 2; pass++) { FindFile ff(d); Array <String> folders; folders.Clear(); while(ff) { if(ff.IsFolder() && ff.GetName() != "Web") folders.Add(p + ff.GetName()); ff.Next(); } Sort(folders); for (int ifold = 0; ifold < folders.GetCount(); ++ifold) { dgen.Generate(x, qtf, folders[ifold], lang, 2, String("/") + FormatInt(di) + "/[" + folders[ifold] + "]"); } d = AppendFileName(uppsrc, "plugin/*.*"); p = "plugin/"; } tt[di].text.Replace("[s5; <#packages#>]", qtf); String toc_qtf; const auto& headers = dgen.GetHeaders(); for (int i = 0; i < headers.GetCount(); i++) { toc_qtf << "[s0;l128; [^topic`:`/`/uppweb`/www`/documentation`$en`-us`#4`_" << IntStr(i + 1) << "^ " << headers[i] << "]&]"; } tt[di].text.Replace("[s0;l128; <#packages`_toc#>&]", toc_qtf); } } bi << BarLink(Www("Tutorials", lang), t_("Tutorials")); bi << BarLink(Www("UppHub", lang, "topic://ide/app/"), t_("UppHub")); bi << BarLink(Www("Roadmap", lang), t_("Status & Roadmap")); bi << BarLink(Www("FAQ", lang), t_("FAQ")); bi << BarLink(Www("About", lang, "topic://ide/app/"), t_("Authors & License")); bi << BarLink("https://www.ultimatepp.org/forums", t_("Forums")); // bcom << BarLink(Www("mailing"), "Mailing lists"); // bi << BarLink("http://www.ultimatepp.org/wiki/index.php", "Wiki"); bi << BarLink(Www("Funding", lang), t_("Funding U++")); // bcom << BarLink(Www("helpus"), "Getting involved"); // bcom << BarLink("mailto: upp@ntllib.org", "Contact developers"); bsearch << BarCaption(t_("Search on this site")); bsearch << SearchBar("ultimatepp.org"); HtmlTag bf = HtmlPackedTable() .Width(-100) .BgColor(White) .Attr("style", "border-style: solid; border-width: 1px; border-color: #6E89AE;" "padding: 0px"); String div = HtmlTable().Border(0).Width(-100) / HtmlLine(); bar[i] = bf / bi + div + // bf / bex + div + // bf / bdoc + div + // bf / bcom + div + // bf / bcon + div + bf / bsearch + div; // bf / blang + div; } SetLanguage(currentLang); for(int i = 0; i < tt.GetCount(); i++) { String topic = tt.GetKey(i); links.Add(topic, topic == webtopic + "/www/index$en-us" ? "index.html" : memcmp(topic, "topic://", 8) ? topic : TopicFileNameHtml(topic, false)); } for(int i = 0; i < tt.GetCount(); i++) { if(tt[i].title == "Nightly builds" || tt[i].title.Find("Download") >= 0) tt[i].text.Replace(String("<#downloads#>"), downloads); else if (links[i].Find("index") >= 0) { String win32 = "upp-win32-RELEASE.exe"; String win32release = win32; win32release.Replace(String("RELEASE"), release); String x11 = "upp-x11-src-RELEASE.tar.gz"; String x11release = x11; x11release.Replace(String("RELEASE"), release); tt[i].text.Replace(DeQtf(x11), DeQtf(x11release)); tt[i].text.Replace(DeQtf(win32), DeQtf(win32release)); } } for(int i = 0; i < reflink.GetCount(); i++) { String l = reflink.GetKey(i); String lbl = Filter(l, CharFilterLbl); String f = links.Get(reflink[i], Null) + '#' + lbl; links.Add(l, f); static const char *x[] = { "::struct", "::class", "::union" }; for(int ii = 0; ii < 3; ii++) { String e = x[ii]; if(EndsWith(l, e)) { links.Add(l.Mid(0, l.GetLength() - e.GetLength()), f); } } labels.Add(l, lbl); } lastUpdate = HtmlItalic() / HtmlArial(8) / HtmlFontColor(Gray()) / (String().Cat() << "Last update " << GetSysDate()); RLOG("Creating htmls"); for(int i = 0; i < tt.GetCount(); i++) ExportPage(i); SetLanguage(currentLang); FileCopy(AppendFileName(uppbox, "uppweb/favicon.png"), AppendFileName(targetdir, "favicon.png")); // rootdir = devdir; targetdir << "/dev"; RLOG("Finished OK"); }