unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / tools / src / tools / configtool / standalone / wxwin / docsystem.cpp
1 //####COPYRIGHTBEGIN####
2 //
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
5 //
6 // This program is part of the eCos host tools.
7 //
8 // This program is free software; you can redistribute it and/or modify it
9 // under the terms of the GNU General Public License as published by the Free
10 // Software Foundation; either version 2 of the License, or (at your option)
11 // any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but WITHOUT
14 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16 // more details.
17 //
18 // You should have received a copy of the GNU General Public License along with
19 // this program; if not, write to the Free Software Foundation, Inc.,
20 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 //
22 // ----------------------------------------------------------------------------
23 //
24 //####COPYRIGHTEND####
25 // docsystem.cpp :
26 //
27 //===========================================================================
28 //#####DESCRIPTIONBEGIN####
29 //
30 // Author(s):   julians
31 // Contact(s):  julians
32 // Date:        2001/04/04
33 // Version:     $Id$
34 // Purpose:
35 // Description: Various classes for the documentation system
36 // Requires:
37 // Provides:
38 // See also:
39 // Known bugs:
40 // Usage:
41 //
42 //####DESCRIPTIONEND####
43 //
44 //===========================================================================
45
46 // ============================================================================
47 // declarations
48 // ============================================================================
49
50 // ----------------------------------------------------------------------------
51 // headers
52 // ----------------------------------------------------------------------------
53 #ifdef __GNUG__
54 #pragma implementation "docsystem.h"
55 #endif
56
57 // Includes other headers for precompiled compilation
58 #include "ecpch.h"
59
60 #ifdef __BORLANDC__
61 #pragma hdrstop
62 #endif
63
64 #include "wx/dir.h"
65 #include "wx/file.h"
66 #include "wx/wfstream.h"
67 #include "wx/progdlg.h"
68 #include "docsystem.h"
69 #include "htmlparser.h"
70 #include "configtooldoc.h"
71 #include "mainwin.h"
72 #include "shortdescrwin.h"
73
74 /*
75  * ecHtmlIndexer
76  * A class to parse files and generate suitable MS Html Help/wxHTML Help compatible
77  * project, contents and keyword files.
78  */
79
80 ecHtmlIndexer::ecHtmlIndexer(bool useRelativeURLs)
81 {
82 #if ecDOCSYSTEM_USE_RELATIVE_URLS
83     m_useRelativeURLs = useRelativeURLs;
84 #else
85     m_useRelativeURLs = FALSE;
86 #endif
87     m_useOldDocs = TRUE;
88
89     // Initialise some tables
90     AddTutorialDirectory(wxT("arm"), wxT("ARM"));
91     AddTutorialDirectory(wxT("am31-33"), wxT("AM31-33"));
92     AddTutorialDirectory(wxT("i386pc"), wxT("i386 PC"));
93     AddTutorialDirectory(wxT("ppc"), wxT("PowerPC"));
94     AddTutorialDirectory(wxT("sh3"), wxT("SH-3"));
95     AddTutorialDirectory(wxT("sparclite"), wxT("SPARClite"));
96     AddTutorialDirectory(wxT("mips"), wxT("MIPS"));
97     AddTutorialDirectory(wxT("v850"), wxT("V850"));
98
99     AddEntityTranslation(wxT("—"), wxT("--"));
100     AddEntityTranslation(wxT("&"), wxT("&"));
101     AddEntityTranslation(wxT("“"), wxT("\""));
102     AddEntityTranslation(wxT("”"), wxT("\""));
103     AddEntityTranslation(wxT("["), wxT("["));
104     AddEntityTranslation(wxT("]"), wxT("]"));
105 }
106
107 ecHtmlIndexer::~ecHtmlIndexer()
108 {
109     ClearItems();
110 }
111
112 // Append HHC-compatible code to a stream according to the tags found in the
113 // given HTML file.
114 /*
115
116 Find the name and URL from a chunk of HTML like
117 the following.
118
119 <P CLASS="ChapterTitleTOC">
120   <A NAME="pgfId=141252">
121   </A>
122   <A HREF="ecos-tutorial.4.html#pgfId=1065474" CLASS="Index">
123      Documentation Roadmap
124   </A>
125      <EM CLASS="PageNumber"></EM>
126 </P>
127
128 We need to output something like this:
129
130     <UL>
131     <LI> <OBJECT type="text/sitemap"><param name="Name" value="Getting Started with eCos"><param name="Local" value="tutorials/arm/ecos-tutorial.1.html"></OBJECT>
132     <LI> <UL>
133            <LI> <OBJECT type="text/sitemap"><param name="Name" value="ARM"><param name="Local" value="tutorials/arm/ecos-tutorial.1.html"></OBJECT>
134            <LI> <UL>
135                   <LI><OBJECT type="text/sitemap"><param name="Name" value="Getting Started with eCos"><param name="Local" value="tutorials/arm/ecos-tutorial.1.html#pgfId=2052424"></OBJECT>
136                   <LI><OBJECT type="text/sitemap"><param name="Name" value="Foreword"><param name="Local" value="tutorials/arm/ecos-tutorial.3.html#pgfId=1065235"></OBJECT>
137                   <LI><OBJECT type="text/sitemap"><param name="Name" value="Documentation Roadmap"><param name="Local" value="tutorials/arm/ecos-tutorial.4.html#pgfId=1065474"></OBJECT>
138                   <LI><UL>
139                         <LI><OBJECT type="text/sitemap"><param name="Name" value="Getting Started with eCos"><param name="Local" value="tutorials/arm/ecos-tutorial.4.html#pgfId=1046487"></OBJECT>
140                         <LI><OBJECT type="text/sitemap"><param name="Name" value="eCos User's Guide"><param name="Local" value="tutorials/arm/ecos-tutorial.4.html#pgfId=1046592"></OBJECT>
141                         <LI><OBJECT type="text/sitemap"><param name="Name" value="eCos Reference Manual"><param name="Local" value="tutorials/arm/ecos-tutorial.4.html#pgfId=1046692"></OBJECT>
142                       </UL>
143                 </UL>
144          </UL>
145   </UL>
146
147 */
148
149 bool ecHtmlIndexer::CreateHHCByExaminingClass(const wxString& title, const wxString& topURL, const wxString& htmlFile, const wxString& docDir, wxOutputStream& stream, int startIndent)
150 {
151     if (!wxFileExists(htmlFile))
152         return FALSE;
153
154     wxString sep(wxFILE_SEP_PATH);
155     wxString pathPrefix(wxPathOnly(htmlFile));
156     if (!wxIsAbsolutePath(htmlFile))
157     {
158         pathPrefix = pathPrefix.Mid(docDir.Length() + 1);
159     }
160
161     wxString topURL1(topURL);
162     if (!UseRelativeURLs() && !wxIsAbsolutePath(topURL1))
163         topURL1 = docDir + sep + topURL1;
164
165     wxSimpleHtmlParser parser;
166     if (parser.ParseFile(htmlFile))
167     {
168         stream << "<LI> <OBJECT type=\"text/sitemap\"><param name=\"Name\" value=\"";
169         stream << TranslateEntities(title) << wxString("\">");
170         
171         if (!topURL.IsEmpty())
172         {
173             stream << "<param name=\"Local\" value=\"";
174             stream << topURL1 << "\"></OBJECT>";
175         }
176         stream << "\n";
177         int indent = startIndent;
178         wxSimpleHtmlTag* tag = parser.GetTopLevelTag()->GetChildren();
179
180         while (tag)
181         {
182             if (tag->GetType() == wxSimpleHtmlTag_Open)
183             {
184                 wxSimpleHtmlAttribute* attr = NULL;
185                 if ((tag->NameIs("P") || tag->NameIs("DIV") ||
186                      tag->NameIs("H1") || tag->NameIs("H2") || tag->NameIs("H3") || tag->NameIs("H4"))
187                      &&
188                      (attr = tag->FindAttribute("CLASS")))
189                 {
190                     int level = -1;
191                     if (attr->HasValue("Level1IX") ||
192                         attr->HasValue("SectionTitleTOC") ||
193                         attr->HasValue("IndexTitleTOC"))
194                         level = 1;
195
196                     else if (attr->HasValue("Level2IX") ||
197                         attr->HasValue("ChapterTitleTOC") ||
198                         attr->HasValue("IntroTitleTOC"))
199                         level = 2;
200
201                     else if (attr->HasValue("Heading1TOC"))
202                         level = 3;
203
204                     else if (attr->HasValue("Heading2TOC"))
205                         level = 4;
206
207                     if (level > -1)
208                     {
209                         wxSimpleHtmlTag* aTag = tag->FindTag("A", "HREF");
210                         if (aTag)
211                             CreateHHCOutputItem(aTag, level, indent, pathPrefix, docDir, stream);
212                     }
213                 }
214             }
215             tag = tag->GetNext();
216         }
217
218         // Close any remaining levels
219         int i;
220         while (indent > startIndent)
221         {
222             indent --;
223             for (i = 0; i < indent*2; i++) stream << " ";
224             stream << "</UL>\n";
225         }
226
227         return TRUE;
228     }
229     else
230         return FALSE;    
231 }
232
233 // Append HHC-compatible code to a stream according to the tags found in the
234 // given HTML file. Use level of <DL> to determine contents heading level.
235
236 /*
237
238 Find the name and URL from a chunk of HTML like
239 the following.
240
241 <DL>
242   <DT>
243   <B>Table of Contents</B>
244   </DT>
245   <DT>
246   1. <A HREF="overview.html">Overview</A>
247   </DT>
248   <DD>
249     <DL>
250       <DT>
251       <A HREF="overview.html#OVERVIEW.TERMINOLOGY">Terminology</A>
252       </DT>
253       <DD>
254         <DL>
255           <DT>
256           <A HREF="overview.html#CONCEPTS.TERMINOLOGY.FRAMEWORK">Component Framework</A>
257           </DT>
258
259   ...
260
261     <UL>
262     <LI> <OBJECT type="text/sitemap"><param name="Name" value="Getting Started with eCos"><param name="Local" value="tutorials/arm/ecos-tutorial.1.html"></OBJECT>
263     <LI> <UL>
264            <LI> <OBJECT type="text/sitemap"><param name="Name" value="ARM"><param name="Local" value="tutorials/arm/ecos-tutorial.1.html"></OBJECT>
265            <LI> <UL>
266                   <LI><OBJECT type="text/sitemap"><param name="Name" value="Getting Started with eCos"><param name="Local" value="tutorials/arm/ecos-tutorial.1.html#pgfId=2052424"></OBJECT>
267                   <LI><OBJECT type="text/sitemap"><param name="Name" value="Foreword"><param name="Local" value="tutorials/arm/ecos-tutorial.3.html#pgfId=1065235"></OBJECT>
268                   <LI><OBJECT type="text/sitemap"><param name="Name" value="Documentation Roadmap"><param name="Local" value="tutorials/arm/ecos-tutorial.4.html#pgfId=1065474"></OBJECT>
269                   <LI><UL>
270                         <LI><OBJECT type="text/sitemap"><param name="Name" value="Getting Started with eCos"><param name="Local" value="tutorials/arm/ecos-tutorial.4.html#pgfId=1046487"></OBJECT>
271                         <LI><OBJECT type="text/sitemap"><param name="Name" value="eCos User's Guide"><param name="Local" value="tutorials/arm/ecos-tutorial.4.html#pgfId=1046592"></OBJECT>
272                         <LI><OBJECT type="text/sitemap"><param name="Name" value="eCos Reference Manual"><param name="Local" value="tutorials/arm/ecos-tutorial.4.html#pgfId=1046692"></OBJECT>
273                       </UL>
274                 </UL>
275          </UL>
276   </UL>
277
278 */
279
280 bool ecHtmlIndexer::CreateHHCByExaminingList(const wxString& title, const wxString& topURL, const wxString& htmlFile, const wxString& docDir, wxOutputStream& stream, int startIndent)
281 {
282     if (!wxFileExists(htmlFile))
283         return FALSE;
284
285     // The path prefix is the path relative to the doc dir
286     wxString sep(wxFILE_SEP_PATH);
287     wxString pathPrefix(wxPathOnly(htmlFile));
288     if (!wxIsAbsolutePath(htmlFile))
289     {
290         pathPrefix = pathPrefix.Mid(docDir.Length() + 1);
291     }
292
293     wxString topURL1(topURL);
294     if (!UseRelativeURLs() && !wxIsAbsolutePath(topURL1))
295         topURL1 = docDir + sep + topURL1;
296
297     wxSimpleHtmlParser parser;
298     if (parser.ParseFile(htmlFile))
299     {
300         stream << "<LI> <OBJECT type=\"text/sitemap\"><param name=\"Name\" value=\"";
301         stream << TranslateEntities(title) << wxString("\">");
302         
303         if (!topURL.IsEmpty())
304         {
305             stream << "<param name=\"Local\" value=\"";
306             stream << topURL1 << "\"></OBJECT>";
307         }
308         stream << "\n";
309         int indent = startIndent; int level = 0;
310         wxSimpleHtmlTag* tag = parser.GetTopLevelTag()->GetChildren();
311
312         while (tag)
313         {
314             if (tag->GetType() == wxSimpleHtmlTag_Open && tag->NameIs("DL")) level ++ ;
315             if (tag->GetType() == wxSimpleHtmlTag_Close && tag->NameIs("DL")) level -- ;
316             if (tag->GetType() == wxSimpleHtmlTag_Open && tag->NameIs("A") && tag->HasAttribute("HREF") && level > 0)
317                 CreateHHCOutputItem(tag, level, indent, pathPrefix, docDir, stream);
318
319             // If we get to list of figures/tables/examples, finish
320             if (tag->GetType() == wxSimpleHtmlTag_Text)
321             {
322                 if (tag->GetText() == wxT("List of Figures") ||
323                     tag->GetText() == wxT("List of Tables") ||
324                     tag->GetText() == wxT("List of Examples"))
325                 {
326                     tag = NULL;
327                 }
328             }
329
330             if (tag)
331                 tag = tag->GetNext();
332         }
333
334         // Close any remaining levels
335         int i;
336         while (indent > startIndent)
337         {
338             indent --;
339             for (i = 0; i < indent*2; i++) stream << " ";
340             stream << "</UL>\n";
341         }
342         return TRUE;
343     }
344     else
345         return FALSE;   
346 }
347
348 // Just add the given contents item without parsing
349 bool ecHtmlIndexer::CreateHHCItem(const wxString& title, const wxString& topURL, const wxString& docDir, wxOutputStream& stream, int indent)
350 {
351     wxString sep(wxFILE_SEP_PATH);
352     wxString topURL1(topURL);
353     if (!UseRelativeURLs())
354         topURL1 = docDir + sep + topURL1;
355
356     int i;
357     for (i = 0; i < indent*2; i++) stream << " ";
358     
359     stream << "<LI> <OBJECT type=\"text/sitemap\"><param name=\"Name\" value=\"";
360     stream << TranslateEntities(title) << "\"><param name=\"Local\" value=\"";
361     stream << topURL1 << "\"></OBJECT>\n";
362
363     return TRUE;
364 }
365
366 void ecHtmlIndexer::CreateHHCOutputItem(wxSimpleHtmlTag* tag, int level, int& indent, const wxString& pathPrefix, const wxString& docDir, wxOutputStream& stream)
367 {
368     wxString url, text;
369     tag->GetAttributeValue(url, "HREF");
370     tag->FindTextUntilTagClose(text, "A");
371     text.Trim(TRUE); // Trim spaces from right of string
372     text.Replace("\n", " "); // Remove newlines
373
374     // Need to adjust the URL to give the path relative to where the index is
375     url = pathPrefix + wxString(wxT("/")) + url;
376
377     wxString sep(wxFILE_SEP_PATH);
378     wxString url1(url);
379     if (!UseRelativeURLs() && !wxIsAbsolutePath(url))
380         url1 = docDir + sep + url;
381
382     int i;
383     while (level > indent)
384     {
385         for (i = 0; i < indent*2; i++) stream << " ";
386
387         stream << "<UL>";
388         indent ++;
389
390         // If we're skipping one or more levels, we need to insert
391         // a dummy node.
392         if (level > indent)
393         {
394             stream << "\n";
395             for (i = 0; i < indent*2; i++) stream << " ";
396
397             stream << "<LI> <OBJECT type=\"text/sitemap\"><param name=\"Name\" value=\"";
398             stream << TranslateEntities(text) << "\"><param name=\"Local\" value=\"";
399             stream << url1 << "\"></OBJECT>";
400         }
401         stream << "\n";
402     }
403
404     while (level < indent)
405     {
406         indent--;
407         for (i = 0; i < indent*2; i++) stream << " ";
408
409         stream << "</UL>\n";
410     }
411
412     for (i = 0; i < indent*2; i++) stream << " ";
413
414     stream << "<LI> <OBJECT type=\"text/sitemap\"><param name=\"Name\" value=\"";
415     stream << TranslateEntities(text) << "\"><param name=\"Local\" value=\"";
416     stream << url1 << "\"></OBJECT>\n";
417 }
418
419 void ecHtmlIndexer::CreateHHCWriteHeader(wxOutputStream& stream)
420 {
421     stream << "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n";
422     stream << "<HTML>\n<HEAD>\n<meta name=\"GENERATOR\" content=\"Microsoft&reg; HTML Help Workshop 4.1\">\n";
423     stream << "<!-- Sitemap 1.0 -->\n</HEAD><BODY>\n";
424     stream << "<UL>\n";
425 }
426
427 void ecHtmlIndexer::CreateHHCWriteFooter(wxOutputStream& stream)
428 {
429     stream << "</UL>\n";
430     stream << "</BODY></HTML>";
431 }
432
433 bool ecHtmlIndexer::CreateHHCStartSection(const wxString& title, const wxString& topURL, const wxString& docDir, wxOutputStream& stream)
434 {
435     wxString sep(wxFILE_SEP_PATH);
436     wxString url1(topURL);
437     if (!UseRelativeURLs() && !wxIsAbsolutePath(url1))
438         url1 = docDir + sep + url1;
439
440     stream << "<LI> <OBJECT type=\"text/sitemap\"><param name=\"Name\" value=\"";
441     stream << TranslateEntities(title) << wxString("\">");
442     
443     if (!topURL.IsEmpty())
444     {
445         stream << "<param name=\"Local\" value=\"";
446         stream << url1 << "\">" ;
447     }
448     stream << "</OBJECT>\n<UL>\n" ;
449     return TRUE;
450 }
451
452 bool ecHtmlIndexer::CreateHHCEndSection(wxOutputStream& stream)
453 {
454     stream << "</UL>\n";
455     return TRUE;
456 }
457
458 // Write the project file
459 bool ecHtmlIndexer::WriteHHP(const wxString& filename, const wxString& docDir)
460 {
461     wxFileOutputStream stream(filename);
462
463     wxString sep(wxFILE_SEP_PATH);
464     wxString path, name, ext;
465     wxSplitPath(filename, & path, & name, & ext);
466
467     wxString compiledFile(name + wxT(".chm"));
468     wxString contentsFile(name + wxT(".hhc"));
469     wxString keywordFile(name + wxT(".hhk"));
470
471     stream << "[OPTIONS]\n\
472 Auto Index=Yes\n\
473 Binary Index=No\n\
474 Compatibility=1.1 or later\n\
475 Compiled file=";
476     stream << compiledFile << "\nContents file=" << contentsFile << "\n";
477     stream << 
478 "Default Window=mainwin\n\
479 Default topic=";
480     if (!UseRelativeURLs())
481         stream << docDir + sep;
482     stream << wxT("index.html") << "\n\
483 Display compile progress=Yes\n\
484 Full-text search=Yes\n" <<
485
486 // Index file=" << keywordFile << "\n
487
488 "Language=0x409 English (United States)\n\
489 Title=eCos\n";
490
491     stream << 
492 "[WINDOWS]\n\
493 mainwin=\"eCos Documentation\",\"eCos.hhc\",,,\"index.html\",\"http://sources.redhat.com/ecos/\",\"Net Release\",\"http://www.redhat.com/products/ecos/\",\"eCos Product\",0x40060420,,0xc287e,[0,0,762,400],,,,,,,0\n\
494 \n\
495 [FILES]\n\
496 index.html\n\
497 \n\
498 [INFOTYPES]\n" ;
499
500     // When we have the ability to generate a hhk, replace above line with:
501     // mainwin=\"eCos Documentation\",\"eCos.hhc\",\"eCos.hhk\",,\"index.html\",\"http://sources.redhat.com/ecos/\",\"Net Release\",\"http://www.redhat.com/products/ecos/\",\"eCos Product\",0x40060420,,0xc287e,[0,0,762,400],,,,,,,0\n\
502
503     return TRUE;
504
505 }
506
507 // Create a section for all the Packages in the system, using the current document/repository.
508 // TODO: check each URL for redirection.
509 bool ecHtmlIndexer::CreateHHCPackagesSection(const wxString& title, const wxString& topURL, wxOutputStream& stream, const wxString& htmlPath)
510 {
511     ecConfigToolDoc* doc = wxGetApp().GetConfigToolDoc();
512     if (!doc)
513         return FALSE;
514
515     // If we have multiple tutorials or whatever, then we need to repeat this line ONCE
516     // and then generate the multiple files. Otherwise we'll be repeating the same "Getting Started with eCos"
517     // line. I.e. it'll only look right if we only have one tutorial.
518     stream << "<LI> <OBJECT type=\"text/sitemap\"><param name=\"Name\" value=\"";
519     stream << TranslateEntities(title) << wxString("\">");
520     
521     if (!topURL.IsEmpty())
522     {
523         stream << "<param name=\"Local\" value=\"";
524         stream << topURL << "\">" ;
525     }
526     stream << "</OBJECT>\n<UL>\n" ;
527
528     // generate the contents of the add/remove list boxes
529     const std::vector<std::string> & packages = doc->GetCdlPkgData ()->get_packages ();
530
531     std::vector<std::string>::const_iterator package_i;
532     for (package_i = packages.begin (); package_i != packages.end (); package_i++)
533     {
534         //              if (! m_CdlPkgData->is_hardware_package (* package_i)) // do not list hardware packages
535         {
536             const std::vector<std::string> & aliases = doc->GetCdlPkgData ()->get_package_aliases (* package_i);
537             wxString strMacroName = package_i->c_str ();
538
539             // use the first alias (if any) as the package identifier
540             wxString strPackageName = aliases.size () ? aliases [0].c_str () : strMacroName.c_str();
541             ecConfigItem * pItem = doc->Find (strMacroName);
542             if (pItem) // if the package is loaded
543             {
544                 // TODO: what if the package is not loaded? how do we access the URL??
545
546                 wxString url(pItem->GetURL());
547
548                 url = htmlPath + wxString(wxFILE_SEP_PATH) + Redirect(htmlPath, url);
549
550                 stream << "<LI> <OBJECT type=\"text/sitemap\"><param name=\"Name\" value=\"";
551                 stream << TranslateEntities(strPackageName) << wxString("\">");
552                 
553                 if (!url.IsEmpty())
554                 {
555                     stream << "<param name=\"Local\" value=\"";
556                     stream << url << "\">" ;
557                 }
558                 stream << "</OBJECT>\n" ;
559             }
560         }
561     }
562     
563     stream << "</UL>\n";
564     return TRUE;
565 }
566
567 // Keeping looking for redirection until there's none.
568 wxString ecHtmlIndexer::Redirect(const wxString& baseName, const wxString& url)
569 {
570     wxString path(baseName);
571     path += wxFILE_SEP_PATH;
572     path += url;
573
574     wxString relativePath(wxPathOnly(url));
575     
576     wxSimpleHtmlParser parser;
577     if ((path.Find(wxT('#')) == -1) && wxFileExists(path) && parser.ParseFile(path))
578     {
579         wxSimpleHtmlTag* tag = parser.GetTopLevelTag()->GetChildren();
580         
581         wxSimpleHtmlTag* refreshTag = tag->FindTag(wxT("meta"), wxT("http-equiv"));
582         if (refreshTag)
583         {
584             wxString value;
585             if (refreshTag->GetAttributeValue(value, wxT("content")))
586             {
587                 if (!value.AfterFirst(wxT('=')).IsEmpty())
588                     value = value.AfterFirst(wxT('=')) ;
589
590                 wxString newURL(relativePath + wxString(wxFILE_SEP_PATH) + value);
591                 return Redirect(baseName, newURL);
592             }
593         }
594     }
595     return url;
596 }
597
598 bool ecHtmlIndexer::DoIndexDocs(const wxString& reposDir, wxString& projectFile, bool force)
599 {
600     wxString sep(wxFILE_SEP_PATH);
601     
602     wxString docDir(reposDir + sep + wxString(wxT("doc"))) ;
603     
604     // The CVS repository has an HTML subdirectory, but the
605     // packaged version doesn't
606     if (wxDirExists(docDir + sep + wxT("html")))
607         docDir = docDir + sep + wxString(wxT("html"));
608     
609     wxString projectDir = FindIndexFilesDir(reposDir);
610
611     projectFile = projectDir + sep + wxT("eCos.hhp");
612     wxString contentsFile = projectDir + sep + wxT("eCos.hhc");
613     wxString keywordFile = projectDir + sep + wxT("eCos.hhk");
614
615     // See if it's already been generated
616     if (wxFileExists(projectFile) && !force)
617         return TRUE;
618     
619     // Project file
620     if (!WriteHHP(projectFile, docDir))
621         return FALSE;
622     
623     wxFileOutputStream stream(contentsFile);
624
625     if (!stream.Ok())
626         return FALSE;
627
628     // Pop up a progress dialog
629     wxProgressDialog dialog(wxGetApp().GetSettings().GetAppName(),
630         _("Compiling documentation index..."), m_indexItems.Number(),
631         wxGetApp().GetTopWindow());
632     
633     CreateHHCWriteHeader(stream);
634
635     int count = 1;
636     wxNode* node = m_indexItems.First();
637     while (node)
638     {
639         dialog.Update(count);
640         count ++;
641
642         ecIndexItem* item = (ecIndexItem*) node->Data();
643         wxString filename(item->m_urlToExamine);
644         wxString urlFilename(item->m_urlToShow);
645
646         if (!filename.IsEmpty())
647         {
648             if (!wxIsAbsolutePath(filename))
649                 filename = docDir + sep + filename;
650 #ifdef __WXMSW__
651             filename.Replace(wxT("/"), wxT("\\"));
652 #endif
653         }
654
655         // Check that the URL we're going to show is available,
656         // otherwise don't output it
657         bool isOk = TRUE;
658         if (!urlFilename.IsEmpty())
659         {
660             if (!wxIsAbsolutePath(urlFilename))
661                 urlFilename = docDir + sep + urlFilename;
662 #ifdef __WXMSW__
663             urlFilename.Replace(wxT("/"), wxT("\\"));
664 #endif
665             // Remove # part if there is any
666             if (urlFilename.Find(wxT('#')) != -1)
667                 urlFilename = urlFilename.BeforeLast(wxT('#'));
668             if (!wxFileExists(urlFilename))
669                 isOk = FALSE;
670         }
671
672         if (isOk)
673         {
674             switch (item->m_type)
675             {
676             case ecIndexByClass:
677                 {
678                     CreateHHCByExaminingClass(item->m_title, item->m_urlToShow, filename, docDir, stream, item->m_startLevel);
679                     break;
680                 }
681             case ecIndexByList:
682                 {
683                     CreateHHCByExaminingList(item->m_title, item->m_urlToShow, filename, docDir, stream, item->m_startLevel);
684                     break;
685                 }
686             case ecIndexNoParse:
687                 {
688                     CreateHHCItem(item->m_title, item->m_urlToShow, docDir, stream, item->m_startLevel);
689                     break;
690                 }
691             case ecIndexStartSection:
692                 {
693                     CreateHHCStartSection(item->m_title, item->m_urlToShow, docDir, stream);
694                     break;
695                 }
696             case ecIndexEndSection:
697                 {
698                     CreateHHCEndSection(stream);
699                     break;
700                 }
701             default:
702                 {
703                     wxASSERT( FALSE );
704                     break;
705                 }
706             }
707         }
708
709         node = node->Next();
710     }
711     
712     CreateHHCPackagesSection(wxT("Packages"), wxEmptyString, stream, docDir);
713     
714     CreateHHCWriteFooter(stream);
715
716 #if 0 // def __WXGTK__
717     // Hack to restore correct colour to short description window
718     ecShortDescriptionWindow* sdw = wxGetApp().GetMainFrame()->GetShortDescriptionWindow();
719
720     wxColour oldColour = sdw->GetBackgroundColour();
721     if (oldColour.Ok())
722     {
723         sdw->SetBackgroundColour(*wxBLACK);
724         sdw->SetBackgroundColour(oldColour);
725     }
726 #endif
727
728     return TRUE;
729 }
730
731 static bool ecDirectoryWriteable(const wxString& dir)
732 {
733     // See if we can write to it
734     wxString sep(wxFILE_SEP_PATH);
735     wxString testFile = dir + sep + wxT("_test.tmp");
736
737     bool ok = FALSE;
738
739     {
740         wxLogNull log;
741         wxFile file;
742         ok = file.Create(testFile) ;
743         if (ok)
744         {
745             file.Close();
746             wxRemoveFile(testFile);
747         }
748     }
749
750     return ok;
751 }
752
753 // Find appropriate destination directory for writing files to
754 wxString ecHtmlIndexer::FindIndexFilesDir(const wxString& reposDir)
755 {
756     wxString sep(wxFILE_SEP_PATH);
757
758     // First try install dir
759     wxString dir = reposDir;
760
761 #ifdef __WXMSW__
762     if (!ecDirectoryWriteable(dir))
763     {
764         // Try temp directory as a last resort
765         if (!wxGetEnv(wxT("TEMP"), & dir))
766         {
767             dir = wxT("c:\\temp");
768         }
769         return dir;
770     }
771     else
772     {
773         return dir;
774     }
775
776 #else
777     if (!ecDirectoryWriteable(dir))
778     {
779         dir = wxGetHomeDir();
780         if (!ecDirectoryWriteable(dir))
781         {
782             // Try temp directory as a last resort
783             if (!wxGetEnv(wxT("TEMP"), & dir))
784             {
785                 dir = wxT("/tmp");
786             }
787         }
788         else
789         {
790             wxString ecosDir = dir + sep + wxT(".eCosDocs");
791             if (!wxDirExists(ecosDir))
792             {
793                 wxMkdir(ecosDir);
794             }
795             wxString name(ecMakeNameFromPath(reposDir));
796             wxString ecosVerDir = ecosDir + sep + name;
797             if (!wxFileExists(ecosVerDir))
798             {
799                 wxMkdir(ecosVerDir);
800             }
801             dir = ecosVerDir;
802         }
803         return dir;
804     }
805     else
806     {
807         return dir;
808     }
809
810 #endif
811 }
812
813 //// Operations on items
814 void ecHtmlIndexer::AddIndexByClass(const wxString& title, const wxString& urlToShow, const wxString& urlToExamine, int startIndent)
815 {
816     m_indexItems.Append(new ecIndexItem(ecIndexByClass, title, urlToShow, urlToExamine, startIndent));
817 }
818
819 void ecHtmlIndexer::AddIndexByList(const wxString& title, const wxString& urlToShow, const wxString& urlToExamine, int startIndent)
820 {
821     m_indexItems.Append(new ecIndexItem(ecIndexByList, title, urlToShow, urlToExamine, startIndent));
822 }
823
824 void ecHtmlIndexer::AddIndexItem(const wxString& title, const wxString& urlToShow, int startIndent)
825 {
826     m_indexItems.Append(new ecIndexItem(ecIndexNoParse, title, urlToShow, wxEmptyString, startIndent));
827 }
828
829 void ecHtmlIndexer::AddStartSection(const wxString& title, const wxString& urlToShow)
830 {
831     m_indexItems.Append(new ecIndexItem(ecIndexStartSection, title, urlToShow, wxEmptyString));
832 }
833
834 void ecHtmlIndexer::AddEndSection()
835 {
836     m_indexItems.Append(new ecIndexItem(ecIndexEndSection, wxEmptyString, wxEmptyString, wxEmptyString));
837 }
838
839 void ecHtmlIndexer::ClearItems()
840 {
841     wxNode* node = m_indexItems.First();
842     while (node)
843     {
844         ecIndexItem* item = (ecIndexItem*) node->Data();
845         delete item;
846         node = node->Next();
847     }
848     m_indexItems.Clear();
849 }
850
851 // Set m_useOldDocs to TRUE if we find old-style docs
852 bool ecHtmlIndexer::CheckDocEra(const wxString& reposDir)
853 {
854     // We look for tutorials/arm/ecos-tutorial.1.html to see if it's old-style
855     wxString sep(wxFILE_SEP_PATH);
856     
857     wxString docDir(reposDir + sep + wxString(wxT("doc"))) ;
858     
859     // The CVS repository has an HTML subdirectory, but the
860     // packaged version doesn't
861     if (wxDirExists(docDir + sep + wxT("html")))
862         docDir = docDir + sep + wxString(wxT("html"));
863     
864     wxString armTutorial = docDir + sep + wxString(wxT("tutorials")) + sep +
865         wxString(wxT("arm")) + sep + wxString(wxT("ecos-tutorial.1.html")) ;
866
867     m_useOldDocs = wxFileExists(armTutorial);
868     return m_useOldDocs;
869 }
870
871
872 // Top-level function: generate appropriate index files
873 // and place them either in the install directory or if that is read-only,
874 // in the user's .eCos directory.
875 // Returns TRUE and the created project file if successful
876 bool ecHtmlIndexer::IndexDocs(const wxString& reposDir, wxString& projectFile, bool force)
877 {
878     CheckDocEra(reposDir);
879
880     if (UseOldDocs())
881     {
882         // Old-style docs, where HTML is mostly generated from PageMaker
883
884         AddStartSection(wxT("Getting Started with eCos"), wxT(""));
885         AddIndexByClass(wxT("AM31-33"), wxT("tutorials/am31-33/ecos-tutorial.1.html"), wxT("tutorials/am31-33/ecos-tutorial.2.html"));
886         AddIndexByClass(wxT("ARM"), wxT("tutorials/arm/ecos-tutorial.1.html"), wxT("/tutorials/arm/ecos-tutorial.2.html"));
887         AddIndexByClass(wxT("i386 PC"), wxT("tutorials/i386pc/ecos-tutorial.1.html"), wxT("tutorials/i386pc/ecos-tutorial.2.html"));
888         AddIndexByClass(wxT("PowerPC"), wxT("tutorials/ppc/ecos-tutorial.1.html"), wxT("tutorials/ppc/ecos-tutorial.2.html"));
889         AddIndexByClass(wxT("SH-3"), wxT("tutorials/sh3/ecos-tutorial.1.html"), wxT("tutorials/sh3/ecos-tutorial.2.html"));
890         AddIndexByClass(wxT("SPARClite"), wxT("tutorials/sparclite/ecos-tutorial.1.html"), wxT("tutorials/sparclite/ecos-tutorial.2.html"));
891         AddIndexByClass(wxT("MIPS"), wxT("tutorials/mips/ecos-tutorial.1.html"), wxT("tutorials/mips/ecos-tutorial.2.html"));
892         AddIndexByClass(wxT("V850"), wxT("tutorials/v850/ecos-tutorial.1.html"), wxT("tutorials/v850/ecos-tutorial.2.html"));
893         AddEndSection();
894         
895         AddIndexByClass(wxT("eCos User's Guide"), wxT("guides/user-guides.1.html"), wxT("guides/user-guides.2.html"));
896         
897         AddIndexByList(wxT("RedBoot User's Guide"), wxT("redboot/redboot.html"), wxT("redboot/redboot.html"));
898         
899         AddIndexByClass(wxT("Linux Configuration Tool Guide"), wxGetApp().GetFullAppPath(wxT("manual/user-guides.4.html")), wxGetApp().GetFullAppPath(wxT("manual/user-guides.2.html")));
900         
901         AddIndexByList(wxT("eCos Component Writer's Guide"), wxT("cdl/cdl-guide.html"), wxT("cdl/cdl-guide.html"));
902         
903         AddIndexByClass(wxT("eCos Reference Manual"), wxT("ref/ecos-ref.1.html"), wxT("ref/ecos-ref.2.html"));
904         
905         AddIndexByClass(wxT("eCos-EL/IX Compatibility Guide"), wxT("ecos-elix/ecos-elix.html"), wxT("ecos-elix/ecos-elix.1.html"), 1);
906         
907         AddStartSection(wxT("GNUPro Toolkit Reference Manual"));
908         // Start at indent 1 to avoid a spurious level
909         AddIndexByClass(wxT("ARM"), wxT("ref/gnupro-ref/arm/ARM_COMBO_front.html"), wxT("ref/gnupro-ref/arm/ARM_COMBOTOC.html"), 1);
910         AddIndexByClass(wxT("Fujitsu SPARClite"), wxT("ref/gnupro-ref/sparclite/index.html"), wxT("ref/gnupro-ref/sparclite/index.html"));
911         AddIndexByClass(wxT("Matsushita MN10300"), wxT("ref/gnupro-ref/mn10300/am33_front.html"), wxT("ref/gnupro-ref/mn10300/am33toc.html"), 1);
912         AddIndexByClass(wxT("PowerPC"), wxT("ref/gnupro-ref/powerpc/index.html"), wxT("ref/gnupro-ref/powerpc/index.html"));
913         AddIndexByClass(wxT("Toshiba MIPS TX39"), wxT("/gnupro-ref/tx39/index.html"), wxT("/gnupro-ref/tx39/index.html"));
914         
915         // Don't parse HTML, just add this item, if the page exists.
916         // Presumably the HTML can't be parsed for some reason.
917         AddIndexItem(wxT("Toshiba MIPS TX49"), wxT("ref/gnupro-ref/tx49/tx49_ref.html"));
918         
919         AddIndexByClass(wxT("Hitachi SuperH"), wxT("ref/gnupro-ref/sh/SH_front.html"), wxT("ref/gnupro-ref/sh/SHTOC.html"), 1);
920         
921         AddIndexItem(wxT("NEC V850"), wxT("ref/gnupro-ref/v850/v850_ref_3.html"));
922         AddIndexByClass(wxT("NEC VR4300"), wxT("ref/gnupro-ref/vr4300/Vr43REF_front.html"), wxT("ref/gnupro-ref/vr4300/Vr43REFTOC.html"), 1);
923         AddEndSection();
924     }
925     else
926     {
927         // NEW-STYLE DOCUMENTATION (HTML is generated from SGML)
928
929         // Get a list of all tutorials
930
931         wxArrayString tutorials;
932
933         wxString sep(wxFILE_SEP_PATH);
934         
935         wxString docDir(reposDir + sep + wxString(wxT("doc"))) ;
936         
937         // The CVS repository has an HTML subdirectory, but the
938         // packaged version doesn't
939         if (wxDirExists(docDir + sep + wxT("html")))
940             docDir = docDir + sep + wxString(wxT("html"));
941
942         docDir += sep ;
943         docDir += wxString(wxT("tutorials"));
944
945         wxLogNull log;
946         wxDir dir(docDir);
947         
948         if (dir.IsOpened())
949         {
950             wxString filename;
951             bool cont = dir.GetFirst(& filename, wxT("*"), wxDIR_DIRS);
952             while (cont)
953             {
954                 if (filename != wxT(".") && filename != wxT(".."))
955                     tutorials.Add(filename);
956                 
957                 cont = dir.GetNext(& filename);
958             }
959         }
960
961         AddStartSection(wxT("Getting Started with eCos"), wxT(""));
962         size_t i;
963         for (i = 0; i < tutorials.GetCount(); i++)
964         {
965             wxString tutorial(tutorials[i]);
966             wxString tutorialRelativePath = wxT("tutorials/") + tutorial + wxT("/ecos-tutorial.html");
967
968             // Use a more friendly name than just the directory if it's available
969             AddIndexByList(TranslateTutorialDirectory(tutorial), tutorialRelativePath, tutorialRelativePath);
970         }
971         AddEndSection();
972
973         AddIndexByList(wxT("eCos User's Guide"), wxT("guides/ecos-user-guide.html"), wxT("guides/ecos-user-guide.html"));
974         AddIndexByList(wxT("RedBoot User's Guide"), wxT("redboot/redboot.html"), wxT("redboot/redboot.html"));
975         AddIndexByList(wxT("eCos Component Writer's Guide"), wxT("cdl/cdl-guide.html"), wxT("cdl/cdl-guide.html"));       
976         AddIndexByList(wxT("eCos Reference Manual"), wxT("ref/ecos-reference-manual.html"), wxT("ref/ecos-reference-manual.html"));
977         AddIndexByList(wxT("eCos-EL/IX Compatibility Guide"), wxT("ecos-elix/elix-compatibility.html"), wxT("ecos-elix/elix-compatibility.html"));
978
979         //// TOOLCHAIN REFERENCE MANUALS
980         AddStartSection(wxT("GNUPro Toolkit Reference Manual"));
981         // Start at indent 1 to avoid a spurious level
982         AddIndexByClass(wxT("ARM"), wxT("ref/gnupro-ref/arm/ARM_COMBO_front.html"), wxT("ref/gnupro-ref/arm/ARM_COMBOTOC.html"), 1);
983         AddIndexByClass(wxT("Fujitsu SPARClite"), wxT("ref/gnupro-ref/sparclite/index.html"), wxT("ref/gnupro-ref/sparclite/index.html"), 1);
984         AddIndexByClass(wxT("Matsushita MN10300"), wxT("ref/gnupro-ref/mn10300/am33_front.html"), wxT("ref/gnupro-ref/mn10300/am33toc.html"), 1);
985         AddIndexByClass(wxT("PowerPC"), wxT("ref/gnupro-ref/powerpc/index.html"), wxT("ref/gnupro-ref/powerpc/index.html"));
986         AddIndexByClass(wxT("Toshiba MIPS TX39"), wxT("/gnupro-ref/tx39/index.html"), wxT("/gnupro-ref/tx39/index.html"));
987         
988         // Don't parse HTML, just add this item, if the page exists.
989         // Presumably the HTML can't be parsed for some reason.
990         AddIndexItem(wxT("Toshiba MIPS TX49"), wxT("ref/gnupro-ref/tx49/tx49_ref.html"));
991         
992         AddIndexByClass(wxT("Hitachi SuperH"), wxT("ref/gnupro-ref/sh/SH_front.html"), wxT("ref/gnupro-ref/sh/SHTOC.html"), 1);
993         
994         AddIndexItem(wxT("NEC V850"), wxT("ref/gnupro-ref/v850/v850_ref_3.html"));
995         AddIndexByClass(wxT("NEC VR4300"), wxT("ref/gnupro-ref/vr4300/Vr43REF_front.html"), wxT("ref/gnupro-ref/vr4300/Vr43REFTOC.html"), 1);
996         AddEndSection();
997     }
998
999     DoIndexDocs(reposDir, projectFile, force);
1000     
1001     return TRUE;
1002 }
1003
1004 // Some things should be translated in the contents
1005 void ecHtmlIndexer::AddEntityTranslation(const wxString& entity, const wxString& translation)
1006 {
1007     m_entityTableNames.Add(entity);
1008     m_entityTableValues.Add(translation);
1009 }
1010
1011 // Apply all translations to this string
1012 wxString ecHtmlIndexer::TranslateEntities(const wxString& toTranslate)
1013 {
1014     wxString result(toTranslate);
1015     size_t i;
1016     for (i = 0; i < m_entityTableNames.GetCount(); i++)
1017     {
1018         result.Replace(m_entityTableNames[i], m_entityTableValues[i]);
1019     }
1020     return result;
1021 }
1022
1023 // Mapping from directory to user-viewable name
1024 void ecHtmlIndexer::AddTutorialDirectory(const wxString& dirName, const wxString& title)
1025 {
1026     m_tutorialTableNames.Add(dirName);
1027     m_tutorialTableValues.Add(title);
1028 }
1029
1030 wxString ecHtmlIndexer::TranslateTutorialDirectory(const wxString& dirName)
1031 {
1032     int i = m_tutorialTableNames.Index(dirName);
1033     if (i >= 0)
1034         return m_tutorialTableValues[i];
1035     else
1036         return dirName;
1037 }
1038