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