]> git.saurik.com Git - wxWidgets.git/blob - utils/tex2rtf/src/htmlutil.cpp
added CSS stylesheets support to tex2rtf
[wxWidgets.git] / utils / tex2rtf / src / htmlutil.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: htmlutil.cpp
3 // Purpose: Converts Latex to HTML
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 7.9.93
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/wx.h"
25 #endif
26
27 #include "tex2any.h"
28 #include "tex2rtf.h"
29 #include "table.h"
30
31
32 extern wxHashTable TexReferences;
33
34
35 extern void DecToHex(int, char *);
36 void GenerateHTMLIndexFile(char *fname);
37
38 void GenerateHTMLWorkshopFiles(char *fname);
39 void HTMLWorkshopAddToContents(int level, char *s, char *file);
40 void HTMLWorkshopStartContents();
41 void HTMLWorkshopEndContents();
42
43 void OutputContentsFrame(void);
44
45 #include "readshg.h" // Segmented hypergraphics parsing
46
47 char *ChaptersName = NULL;
48 char *SectionsName = NULL;
49 char *SubsectionsName = NULL;
50 char *SubsubsectionsName = NULL;
51 char *TitlepageName = NULL;
52 char *lastFileName = NULL;
53 char *lastTopic = NULL;
54 char *currentFileName = NULL;
55 char *contentsFrameName = NULL;
56
57 static TexChunk *descriptionItemArg = NULL;
58 static TexChunk *helpRefFilename = NULL;
59 static TexChunk *helpRefText = NULL;
60 static int indentLevel = 0;
61 static int citeCount = 1;
62 extern FILE *Contents;
63 FILE *FrameContents = NULL;
64 FILE *Titlepage = NULL;
65 // FILE *FrameTitlepage = NULL;
66 int fileId = 0;
67 bool subsectionStarted = FALSE;
68
69 // Which column of a row are we in? (Assumes no nested tables, of course)
70 int currentColumn = 0;
71
72 // Are we in verbatim mode? If so, format differently.
73 static bool inVerbatim = FALSE;
74
75 // Need to know whether we're in a table or figure for benefit
76 // of listoffigures/listoftables
77 static bool inFigure = FALSE;
78 static bool inTable = FALSE;
79
80 // This is defined in the Tex2Any library.
81 extern char *BigBuffer;
82
83 // DHS Two-column table dimensions.
84 static int TwoColWidthA = -1;
85 static int TwoColWidthB = -1;
86
87
88 class HyperReference: public wxObject
89 {
90 public:
91 char *refName;
92 char *refFile;
93 HyperReference(char *name, char *file)
94 {
95 if (name) refName = copystring(name);
96 if (file) refFile = copystring(file);
97 }
98 };
99
100 class TexNextPage: public wxObject
101 {
102 public:
103 char *label;
104 char *filename;
105 TexNextPage(char *theLabel, char *theFile)
106 {
107 label = copystring(theLabel);
108 filename = copystring(theFile);
109 }
110 ~TexNextPage(void)
111 {
112 delete[] label;
113 delete[] filename;
114 }
115 };
116
117 wxHashTable TexNextPages(wxKEY_STRING);
118
119 static char *CurrentChapterName = NULL;
120 static char *CurrentChapterFile = NULL;
121 static char *CurrentSectionName = NULL;
122 static char *CurrentSectionFile = NULL;
123 static char *CurrentSubsectionName = NULL;
124 static char *CurrentSubsectionFile = NULL;
125 static char *CurrentSubsubsectionName = NULL;
126 static char *CurrentSubsubsectionFile = NULL;
127 static char *CurrentTopic = NULL;
128
129 static void SetCurrentTopic(char *s)
130 {
131 if (CurrentTopic) delete[] CurrentTopic;
132 CurrentTopic = copystring(s);
133 }
134
135 void SetCurrentChapterName(char *s, char *file)
136 {
137 if (CurrentChapterName) delete[] CurrentChapterName;
138 CurrentChapterName = copystring(s);
139 if (CurrentChapterFile) delete[] CurrentChapterFile;
140 CurrentChapterFile = copystring(file);
141
142 currentFileName = CurrentChapterFile;
143
144 SetCurrentTopic(s);
145 }
146 void SetCurrentSectionName(char *s, char *file)
147 {
148 if (CurrentSectionName) delete[] CurrentSectionName;
149 CurrentSectionName = copystring(s);
150 if (CurrentSectionFile) delete[] CurrentSectionFile;
151 CurrentSectionFile = copystring(file);
152
153 currentFileName = CurrentSectionFile;
154 SetCurrentTopic(s);
155 }
156 void SetCurrentSubsectionName(char *s, char *file)
157 {
158 if (CurrentSubsectionName) delete[] CurrentSubsectionName;
159 CurrentSubsectionName = copystring(s);
160 if (CurrentSubsectionFile) delete[] CurrentSubsectionFile;
161 CurrentSubsectionFile = copystring(file);
162 currentFileName = CurrentSubsectionFile;
163 SetCurrentTopic(s);
164 }
165 void SetCurrentSubsubsectionName(char *s, char *file)
166 {
167 if (CurrentSubsubsectionName) delete[] CurrentSubsubsectionName;
168 CurrentSubsubsectionName = copystring(s);
169 if (CurrentSubsubsectionFile) delete[] CurrentSubsubsectionFile;
170 CurrentSubsubsectionFile = copystring(file);
171 currentFileName = CurrentSubsubsectionFile;
172 SetCurrentTopic(s);
173 }
174
175 /*
176 * Close former filedescriptor and reopen using another filename.
177 *
178 */
179
180 void ReopenFile(FILE **fd, char **fileName)
181 {
182 if (*fd)
183 {
184 fprintf(*fd, "\n</FONT></BODY></HTML>\n");
185 fclose(*fd);
186 }
187 fileId ++;
188 char buf[400];
189 if (truncateFilenames)
190 sprintf(buf, "%s%d.htm", FileRoot, fileId);
191 else
192 sprintf(buf, "%s%d.html", FileRoot, fileId);
193 if (*fileName) delete[] *fileName;
194 *fileName = copystring(FileNameFromPath(buf));
195 *fd = fopen(buf, "w");
196 fprintf(*fd, "<HTML>\n");
197 }
198
199 /*
200 * Reopen section contents file, i.e. the index appended to each section
201 * in subsectionCombine mode
202 */
203
204 static char *SectionContentsFilename = NULL;
205 static FILE *SectionContentsFD = NULL;
206
207 void ReopenSectionContentsFile(void)
208 {
209 if ( SectionContentsFD )
210 {
211 fclose(SectionContentsFD);
212 }
213 if ( SectionContentsFilename )
214 delete[] SectionContentsFilename;
215 SectionContentsFD = NULL;
216 SectionContentsFilename = NULL;
217
218 // Create the name from the current section filename
219 if ( CurrentSectionFile )
220 {
221 char buf[256];
222 strcpy(buf, CurrentSectionFile);
223 wxStripExtension(buf);
224 strcat(buf, ".con");
225 SectionContentsFilename = copystring(buf);
226
227 SectionContentsFD = fopen(SectionContentsFilename, "w");
228 }
229 }
230
231
232 /*
233 * Given a TexChunk with a string value, scans through the string
234 * converting Latex-isms into HTML-isms, such as 2 newlines -> <P>.
235 *
236 */
237
238 void ProcessText2HTML(TexChunk *chunk)
239 {
240 bool changed = FALSE;
241 int ptr = 0;
242 int i = 0;
243 char ch = 1;
244 int len = strlen(chunk->value);
245 while (ch != 0)
246 {
247 ch = chunk->value[i];
248
249 // 2 newlines means \par
250 if (!inVerbatim && chunk->value[i] == 10 && ((len > i+1 && chunk->value[i+1] == 10) ||
251 ((len > i+1 && chunk->value[i+1] == 13) &&
252 (len > i+2 && chunk->value[i+2] == 10))))
253 {
254 BigBuffer[ptr] = 0; strcat(BigBuffer, "<P>\n\n"); ptr += 5;
255 i += 2;
256 changed = TRUE;
257 }
258 else if (!inVerbatim && ch == '`' && (len >= i+1 && chunk->value[i+1] == '`'))
259 {
260 BigBuffer[ptr] = '"'; ptr ++;
261 i += 2;
262 changed = TRUE;
263 }
264 else if (!inVerbatim && ch == '`') // Change ` to '
265 {
266 BigBuffer[ptr] = 39; ptr ++;
267 i += 1;
268 changed = TRUE;
269 }
270 else if (ch == '<') // Change < to &lt
271 {
272 BigBuffer[ptr] = 0;
273 strcat(BigBuffer, "&lt;");
274 ptr += 4;
275 i += 1;
276 changed = TRUE;
277 }
278 else if (ch == '>') // Change > to &gt
279 {
280 BigBuffer[ptr] = 0;
281 strcat(BigBuffer, "&gt;");
282 ptr += 4;
283 i += 1;
284 changed = TRUE;
285 }
286 else
287 {
288 BigBuffer[ptr] = ch;
289 i ++;
290 ptr ++;
291 }
292 }
293 BigBuffer[ptr] = 0;
294
295 if (changed)
296 {
297 delete chunk->value;
298 chunk->value = copystring(BigBuffer);
299 }
300 }
301
302 /*
303 * Scan through all chunks starting from the given one,
304 * calling ProcessText2HTML to convert Latex-isms to RTF-isms.
305 * This should be called after Tex2Any has parsed the file,
306 * and before TraverseDocument is called.
307 *
308 */
309
310 void Text2HTML(TexChunk *chunk)
311 {
312 Tex2RTFYield();
313 if (stopRunning) return;
314
315 switch (chunk->type)
316 {
317 case CHUNK_TYPE_MACRO:
318 {
319 TexMacroDef *def = chunk->def;
320
321 if (def && def->ignore)
322 return;
323
324 if (def && (def->macroId == ltVERBATIM || def->macroId == ltVERB || def->macroId == ltSPECIAL))
325 inVerbatim = TRUE;
326
327 wxNode *node = chunk->children.First();
328 while (node)
329 {
330 TexChunk *child_chunk = (TexChunk *)node->Data();
331 Text2HTML(child_chunk);
332 node = node->Next();
333 }
334
335 if (def && (def->macroId == ltVERBATIM || def->macroId == ltVERB || def->macroId == ltSPECIAL))
336 inVerbatim = FALSE;
337
338 break;
339 }
340 case CHUNK_TYPE_ARG:
341 {
342 wxNode *node = chunk->children.First();
343 while (node)
344 {
345 TexChunk *child_chunk = (TexChunk *)node->Data();
346 Text2HTML(child_chunk);
347 node = node->Next();
348 }
349
350 break;
351 }
352 case CHUNK_TYPE_STRING:
353 {
354 if (chunk->value)
355 ProcessText2HTML(chunk);
356 break;
357 }
358 }
359 }
360
361 /*
362 * Add appropriate browse buttons to this page.
363 *
364 */
365
366 void AddBrowseButtons(char *upLabel, char *upFilename,
367 char *previousLabel, char *previousFilename,
368 char *thisLabel, char *thisFilename)
369 {
370 char contentsReferenceBuf[80];
371 char upReferenceBuf[80];
372 char backReferenceBuf[80];
373 char forwardReferenceBuf[80];
374 if (htmlBrowseButtons == HTML_BUTTONS_NONE)
375 return;
376
377 char *contentsReference = NULL;
378 if (htmlBrowseButtons == HTML_BUTTONS_TEXT)
379 contentsReference = ContentsNameString;
380 else
381 {
382 // contentsReference = "<img align=center src=\"contents.gif\" BORDER=0 ALT=\"Contents\">";
383 contentsReference = contentsReferenceBuf;
384 sprintf(contentsReference, "<img align=center src=\"%s\" BORDER=0 ALT=\"Contents\">", ConvertCase("contents.gif"));
385 }
386
387 char *upReference = NULL;
388 if (htmlBrowseButtons == HTML_BUTTONS_TEXT)
389 upReference = UpNameString;
390 else
391 {
392 // upReference = "<img align=center src=\"up.gif\" ALT=\"Up\">";
393 upReference = upReferenceBuf;
394 sprintf(upReference, "<img align=center src=\"%s\" BORDER=0 ALT=\"Up\">", ConvertCase("up.gif"));
395 }
396
397 char *backReference = NULL;
398 if (htmlBrowseButtons == HTML_BUTTONS_TEXT)
399 backReference = "&lt;&lt;";
400 else
401 {
402 // backReference = "<img align=center src=\"back.gif\" ALT=\"Previous\">";
403 backReference = backReferenceBuf;
404 sprintf(backReference, "<img align=center src=\"%s\" BORDER=0 ALT=\"Previous\">", ConvertCase("back.gif"));
405 }
406
407 char *forwardReference = NULL;
408 if (htmlBrowseButtons == HTML_BUTTONS_TEXT)
409 forwardReference = "&gt;&gt;";
410 else
411 {
412 // forwardReference = "<img align=center src=\"forward.gif\" ALT=\"Next\">";
413 forwardReference = forwardReferenceBuf;
414 sprintf(forwardReference, "<img align=center src=\"%s\" BORDER=0 ALT=\"Next\">", ConvertCase("forward.gif"));
415 }
416
417 TexOutput("<CENTER>");
418
419 char buf[200];
420
421 /*
422 * Contents button
423 *
424 */
425
426 if (truncateFilenames)
427 {
428 char buf1[80];
429 strcpy(buf1, ConvertCase(FileNameFromPath(FileRoot)));
430 sprintf(buf, "\n<A HREF=\"%s.%s\">%s</A> ", buf1, ConvertCase("htm"), contentsReference);
431 }
432 else
433 {
434 char buf1[80];
435 strcpy(buf1, ConvertCase(FileNameFromPath(FileRoot)));
436 sprintf(buf, "\n<A HREF=\"%s%s\">%s</A> ", buf1, ConvertCase("_contents.html"), contentsReference);
437 }
438 // TexOutput("<NOFRAMES>");
439 TexOutput(buf);
440 // TexOutput("</NOFRAMES>");
441
442 /*
443 * Up button
444 *
445 */
446
447 if (upLabel && upFilename)
448 {
449 if (strlen(upLabel) > 0)
450 sprintf(buf, "<A HREF=\"%s#%s\">%s</A> ", ConvertCase(upFilename), upLabel, upReference);
451 else
452 sprintf(buf, "<A HREF=\"%s\">%s</A> ", ConvertCase(upFilename), upReference);
453 if (strcmp(upLabel, "contents") == 0)
454 {
455 // TexOutput("<NOFRAMES>");
456 TexOutput(buf);
457 // TexOutput("</NOFRAMES>");
458 }
459 else
460 TexOutput(buf);
461 }
462
463 /*
464 * << button
465 *
466 */
467
468 if (previousLabel && previousFilename)
469 {
470 sprintf(buf, "<A HREF=\"%s#%s\">%s</A> ", ConvertCase(previousFilename), previousLabel, backReference);
471 if (strcmp(previousLabel, "contents") == 0)
472 {
473 // TexOutput("<NOFRAMES>");
474 TexOutput(buf);
475 // TexOutput("</NOFRAMES>");
476 }
477 else
478 TexOutput(buf);
479 }
480 else
481 {
482 // A placeholder so the buttons don't keep moving position
483 sprintf(buf, "%s ", backReference);
484 TexOutput(buf);
485 }
486
487 char *nextLabel = NULL;
488 char *nextFilename = NULL;
489
490 // Get the next page, and record the previous page's 'next' page
491 // (i.e. this page)
492 TexNextPage *nextPage = (TexNextPage *)TexNextPages.Get(thisLabel);
493 if (nextPage)
494 {
495 nextLabel = nextPage->label;
496 nextFilename = nextPage->filename;
497 }
498 if (previousLabel && previousFilename)
499 {
500 TexNextPage *oldNextPage = (TexNextPage *)TexNextPages.Get(previousLabel);
501 if (oldNextPage)
502 {
503 delete oldNextPage;
504 TexNextPages.Delete(previousLabel);
505 }
506 TexNextPage *newNextPage = new TexNextPage(thisLabel, thisFilename);
507 TexNextPages.Put(previousLabel, newNextPage);
508 }
509
510 /*
511 * >> button
512 *
513 */
514
515 if (nextLabel && nextFilename)
516 {
517 sprintf(buf, "<A HREF=\"%s#%s\">%s</A> ", ConvertCase(nextFilename), nextLabel, forwardReference);
518 TexOutput(buf);
519 }
520 else
521 {
522 // A placeholder so the buttons don't keep moving position
523 sprintf(buf, "%s ", forwardReference);
524 TexOutput(buf);
525 }
526
527 /*
528 * Horizontal rule to finish it off nicely.
529 *
530 */
531 TexOutput("</CENTER>");
532 TexOutput("<HR>\n");
533
534 // Update last topic/filename
535 if (lastFileName)
536 delete[] lastFileName;
537 lastFileName = copystring(thisFilename);
538 if (lastTopic)
539 delete[] lastTopic;
540 lastTopic = copystring(thisLabel);
541 }
542
543 // A colour string is either 3 numbers separated by semicolons (RGB),
544 // or a reference to a GIF. Return the filename or a hex string like #934CE8
545 char *ParseColourString(char *bkStr, bool *isPicture)
546 {
547 static char resStr[300];
548 strcpy(resStr, bkStr);
549 char *tok1 = strtok(resStr, ";");
550 char *tok2 = strtok(NULL, ";");
551 if (tok1)
552 {
553 if (!tok2)
554 {
555 *isPicture = TRUE;
556 return resStr;
557 }
558 else
559 {
560 *isPicture = FALSE;
561 char *tok3 = strtok(NULL, ";");
562 if (tok3)
563 {
564 // Now convert 3 strings into decimal numbers, and then hex numbers.
565 int red = atoi(tok1);
566 int green = atoi(tok2);
567 int blue = atoi(tok3);
568
569 strcpy(resStr, "#");
570
571 char buf[3];
572 DecToHex(red, buf);
573 strcat(resStr, buf);
574 DecToHex(green, buf);
575 strcat(resStr, buf);
576 DecToHex(blue, buf);
577 strcat(resStr, buf);
578 return resStr;
579 }
580 else return NULL;
581 }
582 }
583 else return NULL;
584 }
585
586 void OutputFont(void)
587 {
588 // Output <FONT FACE=...>
589 TexOutput("<FONT FACE=\"");
590 if (htmlFaceName)
591 TexOutput(htmlFaceName);
592 else
593 TexOutput("Times New Roman");
594 TexOutput("\">\n");
595 }
596
597 // Output start of <BODY> block
598 void OutputBodyStart(void)
599 {
600 TexOutput("\n<BODY");
601 if (backgroundImageString)
602 {
603 bool isPicture = FALSE;
604 char *s = ParseColourString(backgroundImageString, &isPicture);
605 if (s)
606 {
607 TexOutput(" BACKGROUND=\""); TexOutput(s); TexOutput("\"");
608 }
609 }
610 if (backgroundColourString)
611 {
612 bool isPicture = FALSE;
613 char *s = ParseColourString(backgroundColourString, &isPicture);
614 if (s)
615 {
616 TexOutput(" BGCOLOR="); TexOutput(s);
617 }
618 }
619
620 // Set foreground text colour, if one is specified
621 if (textColourString)
622 {
623 bool isPicture = FALSE;
624 char *s = ParseColourString(textColourString, &isPicture);
625 if (s)
626 {
627 TexOutput(" TEXT="); TexOutput(s);
628 }
629 }
630 // Set link text colour, if one is specified
631 if (linkColourString)
632 {
633 bool isPicture = FALSE;
634 char *s = ParseColourString(linkColourString, &isPicture);
635 if (s)
636 {
637 TexOutput(" LINK="); TexOutput(s);
638 }
639 }
640 // Set followed link text colour, if one is specified
641 if (followedLinkColourString)
642 {
643 bool isPicture = FALSE;
644 char *s = ParseColourString(followedLinkColourString, &isPicture);
645 if (s)
646 {
647 TexOutput(" VLINK="); TexOutput(s);
648 }
649 }
650 TexOutput(">\n");
651
652 OutputFont();
653 }
654
655 void HTMLHead()
656 {
657 TexOutput("<head>");
658 if (htmlStylesheet) {
659 TexOutput("<link rel=stylesheet type=\"text/css\" href=\"");
660 TexOutput(htmlStylesheet);
661 TexOutput("\">");
662 }
663 };
664
665 void HTMLHeadTo(FILE* f)
666 {
667 if (htmlStylesheet)
668 fprintf(f,"<head><link rel=stylesheet type=\"text/css\" href=\"%s\">",htmlStylesheet);
669 else
670 fprintf(f,"<head>");
671 }
672
673 // Called on start/end of macro examination
674 void HTMLOnMacro(int macroId, int no_args, bool start)
675 {
676 switch (macroId)
677 {
678 case ltCHAPTER:
679 case ltCHAPTERSTAR:
680 case ltCHAPTERHEADING:
681 {
682 if (!start)
683 {
684 sectionNo = 0;
685 figureNo = 0;
686 subsectionNo = 0;
687 subsubsectionNo = 0;
688 if (macroId != ltCHAPTERSTAR)
689 chapterNo ++;
690
691 SetCurrentOutput(NULL);
692 startedSections = TRUE;
693
694 char *topicName = FindTopicName(GetNextChunk());
695 ReopenFile(&Chapters, &ChaptersName);
696 AddTexRef(topicName, ChaptersName, ChapterNameString);
697
698 SetCurrentChapterName(topicName, ChaptersName);
699 if (htmlWorkshopFiles) HTMLWorkshopAddToContents(0, topicName, ChaptersName);
700
701 SetCurrentOutput(Chapters);
702
703 HTMLHead();
704 TexOutput("<title>");
705 OutputCurrentSection(); // Repeat section header
706 TexOutput("</title></head>\n");
707 OutputBodyStart();
708
709 char titleBuf[200];
710 if (truncateFilenames)
711 sprintf(titleBuf, "%s.htm", FileNameFromPath(FileRoot));
712 else
713 sprintf(titleBuf, "%s_contents.html", FileNameFromPath(FileRoot));
714
715 fprintf(Chapters, "<A NAME=\"%s\"></A>", topicName);
716
717 AddBrowseButtons("", titleBuf, // Up
718 lastTopic, lastFileName, // Last topic
719 topicName, ChaptersName); // This topic
720
721 fprintf(Contents, "\n<LI><A HREF=\"%s#%s\">", ConvertCase(ChaptersName), topicName);
722
723 if (htmlFrameContents && FrameContents)
724 {
725 SetCurrentOutput(FrameContents);
726 fprintf(FrameContents, "\n<LI><A HREF=\"%s#%s\" TARGET=\"mainwindow\">", ConvertCase(ChaptersName), topicName);
727 OutputCurrentSection();
728 fprintf(FrameContents, "</A>\n");
729 }
730
731 SetCurrentOutputs(Contents, Chapters);
732 fprintf(Chapters, "\n<H2>");
733 OutputCurrentSection();
734 fprintf(Contents, "</A>\n");
735 fprintf(Chapters, "</H2>\n");
736
737 SetCurrentOutput(Chapters);
738
739 // Add this section title to the list of keywords
740 if (htmlIndex)
741 {
742 OutputCurrentSectionToString(wxTex2RTFBuffer);
743 AddKeyWordForTopic(topicName, wxTex2RTFBuffer, ConvertCase(currentFileName));
744 }
745 }
746 break;
747 }
748 case ltSECTION:
749 case ltSECTIONSTAR:
750 case ltSECTIONHEADING:
751 case ltGLOSS:
752 {
753 if (!start)
754 {
755 subsectionNo = 0;
756 subsubsectionNo = 0;
757 subsectionStarted = FALSE;
758
759 if (macroId != ltSECTIONSTAR)
760 sectionNo ++;
761
762 SetCurrentOutput(NULL);
763 startedSections = TRUE;
764
765 char *topicName = FindTopicName(GetNextChunk());
766 ReopenFile(&Sections, &SectionsName);
767 AddTexRef(topicName, SectionsName, SectionNameString);
768
769 SetCurrentSectionName(topicName, SectionsName);
770 if (htmlWorkshopFiles) HTMLWorkshopAddToContents(1, topicName, SectionsName);
771
772 SetCurrentOutput(Sections);
773 HTMLHead();
774 TexOutput("<title>");
775 OutputCurrentSection();
776 TexOutput("</title></head>\n");
777 OutputBodyStart();
778
779 fprintf(Sections, "<A NAME=\"%s\"></A>", topicName);
780 AddBrowseButtons(CurrentChapterName, CurrentChapterFile, // Up
781 lastTopic, lastFileName, // Last topic
782 topicName, SectionsName); // This topic
783
784 FILE *jumpFrom = ((DocumentStyle == LATEX_ARTICLE) ? Contents : Chapters);
785
786 SetCurrentOutputs(jumpFrom, Sections);
787 if (DocumentStyle == LATEX_ARTICLE)
788 fprintf(jumpFrom, "\n<LI><A HREF=\"%s#%s\">", ConvertCase(SectionsName), topicName);
789 else
790 fprintf(jumpFrom, "\n<A HREF=\"%s#%s\"><B>", ConvertCase(SectionsName), topicName);
791
792 fprintf(Sections, "\n<H2>");
793 OutputCurrentSection();
794
795 if (DocumentStyle == LATEX_ARTICLE)
796 fprintf(jumpFrom, "</A>\n");
797 else
798 fprintf(jumpFrom, "</B></A><BR>\n");
799 fprintf(Sections, "</H2>\n");
800
801 SetCurrentOutput(Sections);
802 // Add this section title to the list of keywords
803 if (htmlIndex)
804 {
805 OutputCurrentSectionToString(wxTex2RTFBuffer);
806 AddKeyWordForTopic(topicName, wxTex2RTFBuffer, currentFileName);
807 }
808 }
809 break;
810 }
811 case ltSUBSECTION:
812 case ltSUBSECTIONSTAR:
813 case ltMEMBERSECTION:
814 case ltFUNCTIONSECTION:
815 {
816 if (!start)
817 {
818 if (!Sections)
819 {
820 OnError("You cannot have a subsection before a section!");
821 }
822 else
823 {
824 subsubsectionNo = 0;
825
826 if (macroId != ltSUBSECTIONSTAR)
827 subsectionNo ++;
828
829 if ( combineSubSections && !subsectionStarted )
830 {
831 // Read old .con file in at this point
832 char buf[256];
833 strcpy(buf, CurrentSectionFile);
834 wxStripExtension(buf);
835 strcat(buf, ".con");
836 FILE *fd = fopen(buf, "r");
837 if ( fd )
838 {
839 int ch = getc(fd);
840 while (ch != EOF)
841 {
842 putc(ch, Sections);
843 ch = getc(fd);
844 }
845 fclose(fd);
846 }
847 fprintf(Sections, "<P>\n");
848
849 // Close old file, create a new file for the sub(sub)section contents entries
850 ReopenSectionContentsFile();
851 }
852
853 startedSections = TRUE;
854 subsectionStarted = TRUE;
855
856 char *topicName = FindTopicName(GetNextChunk());
857
858 if ( !combineSubSections )
859 {
860 SetCurrentOutput(NULL);
861 ReopenFile(&Subsections, &SubsectionsName);
862 AddTexRef(topicName, SubsectionsName, SubsectionNameString);
863 SetCurrentSubsectionName(topicName, SubsectionsName);
864 if (htmlWorkshopFiles) HTMLWorkshopAddToContents(2, topicName, SubsectionsName);
865 SetCurrentOutput(Subsections);
866
867 HTMLHead();
868 TexOutput("<title>");
869 OutputCurrentSection();
870 TexOutput("</title></head>\n");
871 OutputBodyStart();
872
873 fprintf(Subsections, "<A NAME=\"%s\"></A>", topicName);
874 AddBrowseButtons(CurrentSectionName, CurrentSectionFile, // Up
875 lastTopic, lastFileName, // Last topic
876 topicName, SubsectionsName); // This topic
877
878 SetCurrentOutputs(Sections, Subsections);
879 fprintf(Sections, "\n<A HREF=\"%s#%s\"><B>", ConvertCase(SubsectionsName), topicName);
880
881 fprintf(Subsections, "\n<H3>");
882 OutputCurrentSection();
883 fprintf(Sections, "</B></A><BR>\n");
884 fprintf(Subsections, "</H3>\n");
885
886 SetCurrentOutput(Subsections);
887 }
888 else
889 {
890 AddTexRef(topicName, SectionsName, SubsectionNameString);
891 SetCurrentSubsectionName(topicName, SectionsName);
892
893 // if ( subsectionNo != 0 )
894 fprintf(Sections, "\n<HR>\n");
895
896 // We're putting everything into the section file
897 fprintf(Sections, "<A NAME=\"%s\"></A>", topicName);
898 fprintf(Sections, "\n<H3>");
899 OutputCurrentSection();
900 fprintf(Sections, "</H3>\n");
901
902 SetCurrentOutput(SectionContentsFD);
903 fprintf(SectionContentsFD, "<A HREF=\"#%s\">", topicName);
904 OutputCurrentSection();
905 TexOutput("</A><BR>\n");
906
907 if (htmlWorkshopFiles) HTMLWorkshopAddToContents(2, topicName, SectionsName);
908 SetCurrentOutput(Sections);
909 }
910 // Add this section title to the list of keywords
911 if (htmlIndex)
912 {
913 OutputCurrentSectionToString(wxTex2RTFBuffer);
914 AddKeyWordForTopic(topicName, wxTex2RTFBuffer, currentFileName);
915 }
916
917 }
918 }
919 break;
920 }
921 case ltSUBSUBSECTION:
922 case ltSUBSUBSECTIONSTAR:
923 {
924 if (!start)
925 {
926 if (!Subsections && !combineSubSections)
927 {
928 OnError("You cannot have a subsubsection before a subsection!");
929 }
930 else
931 {
932 if (macroId != ltSUBSUBSECTIONSTAR)
933 subsubsectionNo ++;
934
935 startedSections = TRUE;
936
937 char *topicName = FindTopicName(GetNextChunk());
938
939 if ( !combineSubSections )
940 {
941 SetCurrentOutput(NULL);
942 ReopenFile(&Subsubsections, &SubsubsectionsName);
943 AddTexRef(topicName, SubsubsectionsName, SubsubsectionNameString);
944 SetCurrentSubsubsectionName(topicName, SubsubsectionsName);
945 if (htmlWorkshopFiles) HTMLWorkshopAddToContents(3, topicName, SubsubsectionsName);
946
947 SetCurrentOutput(Subsubsections);
948 HTMLHead();
949 TexOutput("<title>");
950 OutputCurrentSection();
951 TexOutput("</title></head>\n");
952 OutputBodyStart();
953
954 fprintf(Subsubsections, "<A NAME=\"%s\"></A>", topicName);
955
956 AddBrowseButtons(CurrentSubsectionName, CurrentSubsectionFile, // Up
957 lastTopic, lastFileName, // Last topic
958 topicName, SubsubsectionsName); // This topic
959
960 SetCurrentOutputs(Subsections, Subsubsections);
961 fprintf(Subsections, "\n<A HREF=\"%s#%s\"><B>", ConvertCase(SubsubsectionsName), topicName);
962
963 fprintf(Subsubsections, "\n<H3>");
964 OutputCurrentSection();
965 fprintf(Subsections, "</B></A><BR>\n");
966 fprintf(Subsubsections, "</H3>\n");
967 }
968 else
969 {
970 AddTexRef(topicName, SectionsName, SubsubsectionNameString);
971 SetCurrentSubsectionName(topicName, SectionsName);
972 fprintf(Sections, "\n<HR>\n");
973
974 // We're putting everything into the section file
975 fprintf(Sections, "<A NAME=\"%s\"></A>", topicName);
976 fprintf(Sections, "\n<H3>");
977 OutputCurrentSection();
978 fprintf(Sections, "</H3>\n");
979 /* TODO: where do we put subsubsection contents entry - indented, with subsection entries?
980 SetCurrentOutput(SectionContentsFD);
981 fprintf(SectionContentsFD, "<A HREF=\"#%s\">", topicName);
982 OutputCurrentSection();
983 TexOutput("</A><BR>");
984 */
985 if (htmlWorkshopFiles) HTMLWorkshopAddToContents(2, topicName, SectionsName);
986 SetCurrentOutput(Sections);
987 }
988
989 // Add this section title to the list of keywords
990 if (htmlIndex)
991 {
992 OutputCurrentSectionToString(wxTex2RTFBuffer);
993 AddKeyWordForTopic(topicName, wxTex2RTFBuffer, currentFileName);
994 }
995 }
996 }
997 break;
998 }
999 case ltFUNC:
1000 case ltPFUNC:
1001 {
1002 if ( !combineSubSections )
1003 SetCurrentOutput(Subsections);
1004 else
1005 SetCurrentOutput(Sections);
1006 if (start)
1007 {
1008 }
1009 else
1010 {
1011 }
1012 break;
1013 }
1014 case ltCLIPSFUNC:
1015 {
1016 if ( !combineSubSections )
1017 SetCurrentOutput(Subsections);
1018 else
1019 SetCurrentOutput(Sections);
1020 if (start)
1021 {
1022 }
1023 else
1024 {
1025 }
1026 break;
1027 }
1028 case ltMEMBER:
1029 {
1030 if ( !combineSubSections )
1031 SetCurrentOutput(Subsections);
1032 else
1033 SetCurrentOutput(Sections);
1034 if (start)
1035 {
1036 }
1037 else
1038 {
1039 }
1040 break;
1041 }
1042 case ltVOID:
1043 // if (start)
1044 // TexOutput("<B>void</B>");
1045 break;
1046 case ltHARDY:
1047 if (start)
1048 TexOutput("HARDY");
1049 break;
1050 case ltWXCLIPS:
1051 if (start)
1052 TexOutput("wxCLIPS");
1053 break;
1054 case ltAMPERSAND:
1055 if (start)
1056 TexOutput("&amp;");
1057 break;
1058 case ltSPECIALAMPERSAND:
1059 {
1060 if (start)
1061 {
1062 if (inTabular)
1063 {
1064 // End cell, start cell
1065
1066 TexOutput("</FONT></TD>");
1067
1068 // Start new row and cell, setting alignment for the first cell.
1069 if (currentColumn < noColumns)
1070 currentColumn ++;
1071
1072 char buf[100];
1073 if (TableData[currentColumn].justification == 'c')
1074 sprintf(buf, "\n<TD ALIGN=CENTER>");
1075 else if (TableData[currentColumn].justification == 'r')
1076 sprintf(buf, "\n<TD ALIGN=RIGHT>");
1077 else if (TableData[currentColumn].absWidth)
1078 {
1079 // Convert from points * 20 into pixels.
1080 int points = TableData[currentColumn].width / 20;
1081
1082 // Say the display is 100 DPI (dots/pixels per inch).
1083 // There are 72 pts to the inch. So 1pt = 1/72 inch, or 100 * 1/72 dots.
1084 int pixels = (int)(points * 100.0 / 72.0);
1085 sprintf(buf, "<TD ALIGN=CENTER WIDTH=%d>", pixels);
1086 }
1087 else
1088 sprintf(buf, "\n<TD ALIGN=LEFT>");
1089 TexOutput(buf);
1090 OutputFont();
1091 }
1092 else
1093 TexOutput("&amp;");
1094 }
1095 break;
1096 }
1097 case ltBACKSLASHCHAR:
1098 {
1099 if (start)
1100 {
1101 if (inTabular)
1102 {
1103 // End row. In fact, tables without use of \row or \ruledrow isn't supported for
1104 // HTML: the syntax is too different (e.g. how do we know where to put the first </TH>
1105 // if we've ended the last row?). So normally you wouldn't use \\ to end a row.
1106 TexOutput("</TR>\n");
1107 }
1108 else
1109 TexOutput("<BR>\n");
1110 }
1111 break;
1112 }
1113 case ltROW:
1114 case ltRULEDROW:
1115 {
1116 if (start)
1117 {
1118 currentColumn = 0;
1119
1120 // Start new row and cell, setting alignment for the first cell.
1121 char buf[100];
1122 if (TableData[currentColumn].justification == 'c')
1123 sprintf(buf, "<TR>\n<TD ALIGN=CENTER>");
1124 else if (TableData[currentColumn].justification == 'r')
1125 sprintf(buf, "<TR>\n<TD ALIGN=RIGHT>");
1126 else if (TableData[currentColumn].absWidth)
1127 {
1128 // Convert from points * 20 into pixels.
1129 int points = TableData[currentColumn].width / 20;
1130
1131 // Say the display is 100 DPI (dots/pixels per inch).
1132 // There are 72 pts to the inch. So 1pt = 1/72 inch, or 100 * 1/72 dots.
1133 int pixels = (int)(points * 100.0 / 72.0);
1134 sprintf(buf, "<TR>\n<TD ALIGN=CENTER WIDTH=%d>", pixels);
1135 }
1136 else
1137 sprintf(buf, "<TR>\n<TD ALIGN=LEFT>");
1138 TexOutput(buf);
1139 OutputFont();
1140 }
1141 else
1142 {
1143 // End cell and row
1144 // Start new row and cell
1145 TexOutput("</FONT></TD>\n</TR>\n");
1146 }
1147 break;
1148 }
1149 // HTML-only: break until the end of the picture (both margins are clear).
1150 case ltBRCLEAR:
1151 {
1152 if (start)
1153 TexOutput("<BR CLEAR=ALL>");
1154 break;
1155 }
1156 case ltRTFSP: // Explicit space, RTF only
1157 break;
1158 case ltSPECIALTILDE:
1159 {
1160 if (start)
1161 {
1162 if (inVerbatim)
1163 TexOutput("~");
1164 else
1165 TexOutput(" ");
1166 }
1167 break;
1168 }
1169 case ltINDENTED :
1170 {
1171 if ( start )
1172 TexOutput("<UL><UL>\n");
1173 else
1174 TexOutput("</UL></UL>\n");
1175 break;
1176 }
1177 case ltITEMIZE:
1178 case ltENUMERATE:
1179 case ltDESCRIPTION:
1180 // case ltTWOCOLLIST:
1181 {
1182 if (start)
1183 {
1184 indentLevel ++;
1185
1186 int listType;
1187 if (macroId == ltENUMERATE)
1188 listType = LATEX_ENUMERATE;
1189 else if (macroId == ltITEMIZE)
1190 listType = LATEX_ITEMIZE;
1191 else
1192 listType = LATEX_DESCRIPTION;
1193
1194 itemizeStack.Insert(new ItemizeStruc(listType));
1195 switch (listType)
1196 {
1197 case LATEX_ITEMIZE:
1198 TexOutput("<UL>\n");
1199 break;
1200 case LATEX_ENUMERATE:
1201 TexOutput("<OL>\n");
1202 break;
1203 case LATEX_DESCRIPTION:
1204 default:
1205 TexOutput("<DL>\n");
1206 break;
1207 }
1208 }
1209 else
1210 {
1211 indentLevel --;
1212 if (itemizeStack.First())
1213 {
1214 ItemizeStruc *struc = (ItemizeStruc *)itemizeStack.First()->Data();
1215 switch (struc->listType)
1216 {
1217 case LATEX_ITEMIZE:
1218 TexOutput("</UL>\n");
1219 break;
1220 case LATEX_ENUMERATE:
1221 TexOutput("</OL>\n");
1222 break;
1223 case LATEX_DESCRIPTION:
1224 default:
1225 TexOutput("</DL>\n");
1226 break;
1227 }
1228
1229 delete struc;
1230 delete itemizeStack.First();
1231 }
1232 }
1233 break;
1234 }
1235 case ltTWOCOLLIST :
1236 {
1237 if ( start )
1238 TexOutput("\n<TABLE>\n");
1239 else {
1240 TexOutput("\n</TABLE>\n");
1241 // DHS
1242 TwoColWidthA = -1;
1243 TwoColWidthB = -1;
1244 }
1245 break;
1246 }
1247 case ltPAR:
1248 {
1249 if (start)
1250 TexOutput("<P>\n");
1251 break;
1252 }
1253 /* For footnotes we need to output the text at the bottom of the page and
1254 * insert a reference to it. Is it worth the trouble...
1255 case ltFOOTNOTE:
1256 case ltFOOTNOTEPOPUP:
1257 {
1258 if (start)
1259 {
1260 TexOutput("<FN>);
1261 }
1262 else TexOutput("</FN>");
1263 break;
1264 }
1265 */
1266 case ltVERB:
1267 {
1268 if (start)
1269 TexOutput("<TT>");
1270 else TexOutput("</TT>");
1271 break;
1272 }
1273 case ltVERBATIM:
1274 {
1275 if (start)
1276 {
1277 char buf[100];
1278 sprintf(buf, "<PRE>\n");
1279 TexOutput(buf);
1280 }
1281 else TexOutput("</PRE>\n");
1282 break;
1283 }
1284 case ltCENTERLINE:
1285 case ltCENTER:
1286 {
1287 if (start)
1288 {
1289 TexOutput("<CENTER>");
1290 }
1291 else TexOutput("</CENTER>");
1292 break;
1293 }
1294 case ltFLUSHLEFT:
1295 {
1296 /*
1297 if (start)
1298 {
1299 TexOutput("{\\ql ");
1300 }
1301 else TexOutput("}\\par\\pard\n");
1302 */
1303 break;
1304 }
1305 case ltFLUSHRIGHT:
1306 {
1307 /*
1308 if (start)
1309 {
1310 TexOutput("{\\qr ");
1311 }
1312 else TexOutput("}\\par\\pard\n");
1313 */
1314 break;
1315 }
1316 case ltSMALL:
1317 {
1318 if (start)
1319 {
1320 // Netscape extension
1321 TexOutput("<FONT SIZE=2>");
1322 }
1323 else TexOutput("</FONT>");
1324 break;
1325 }
1326 case ltTINY:
1327 {
1328 if (start)
1329 {
1330 // Netscape extension
1331 TexOutput("<FONT SIZE=1>");
1332 }
1333 else TexOutput("</FONT>");
1334 break;
1335 }
1336 case ltNORMALSIZE:
1337 {
1338 if (start)
1339 {
1340 // Netscape extension
1341 TexOutput("<FONT SIZE=3>");
1342 }
1343 else TexOutput("</FONT>");
1344 break;
1345 }
1346 case ltlarge:
1347 {
1348 if (start)
1349 {
1350 // Netscape extension
1351 TexOutput("<FONT SIZE=4>");
1352 }
1353 else TexOutput("</FONT>");
1354 break;
1355 }
1356 case ltLarge:
1357 {
1358 if (start)
1359 {
1360 // Netscape extension
1361 TexOutput("<FONT SIZE=5>");
1362 }
1363 else TexOutput("</FONT>");
1364 break;
1365 }
1366 case ltLARGE:
1367 {
1368 if (start)
1369 {
1370 // Netscape extension
1371 TexOutput("<FONT SIZE=6>");
1372 }
1373 else TexOutput("</FONT>");
1374 break;
1375 }
1376 case ltBFSERIES:
1377 case ltTEXTBF:
1378 case ltBF:
1379 {
1380 if (start)
1381 {
1382 TexOutput("<B>");
1383 }
1384 else TexOutput("</B>");
1385 break;
1386 }
1387 case ltITSHAPE:
1388 case ltTEXTIT:
1389 case ltIT:
1390 {
1391 if (start)
1392 {
1393 TexOutput("<I>");
1394 }
1395 else TexOutput("</I>");
1396 break;
1397 }
1398 case ltEMPH:
1399 case ltEM:
1400 {
1401 if (start)
1402 {
1403 TexOutput("<EM>");
1404 }
1405 else TexOutput("</EM>");
1406 break;
1407 }
1408 case ltUNDERLINE:
1409 {
1410 if (start)
1411 {
1412 TexOutput("<UL>");
1413 }
1414 else TexOutput("</UL>");
1415 break;
1416 }
1417 case ltTTFAMILY:
1418 case ltTEXTTT:
1419 case ltTT:
1420 {
1421 if (start)
1422 {
1423 TexOutput("<TT>");
1424 }
1425 else TexOutput("</TT>");
1426 break;
1427 }
1428 case ltCOPYRIGHT:
1429 {
1430 if (start)
1431 TexOutput("&copy;", TRUE);
1432 break;
1433 }
1434 case ltREGISTERED:
1435 {
1436 if (start)
1437 TexOutput("&reg;", TRUE);
1438 break;
1439 }
1440 // Arrows
1441 case ltLEFTARROW:
1442 {
1443 if (start) TexOutput("&lt;--");
1444 break;
1445 }
1446 case ltLEFTARROW2:
1447 {
1448 if (start) TexOutput("&lt;==");
1449 break;
1450 }
1451 case ltRIGHTARROW:
1452 {
1453 if (start) TexOutput("--&gt;");
1454 break;
1455 }
1456 case ltRIGHTARROW2:
1457 {
1458 if (start) TexOutput("==&gt;");
1459 break;
1460 }
1461 case ltLEFTRIGHTARROW:
1462 {
1463 if (start) TexOutput("&lt;--&gt;");
1464 break;
1465 }
1466 case ltLEFTRIGHTARROW2:
1467 {
1468 if (start) TexOutput("&lt;==&gt;");
1469 break;
1470 }
1471 /*
1472 case ltSC:
1473 {
1474 break;
1475 }
1476 */
1477 case ltITEM:
1478 {
1479 if (!start)
1480 {
1481 wxNode *node = itemizeStack.First();
1482 if (node)
1483 {
1484 ItemizeStruc *struc = (ItemizeStruc *)node->Data();
1485 struc->currentItem += 1;
1486 if (struc->listType == LATEX_DESCRIPTION)
1487 {
1488 if (descriptionItemArg)
1489 {
1490 TexOutput("<DT> ");
1491 TraverseChildrenFromChunk(descriptionItemArg);
1492 TexOutput("\n");
1493 descriptionItemArg = NULL;
1494 }
1495 TexOutput("<DD>");
1496 }
1497 else
1498 TexOutput("<LI>");
1499 }
1500 }
1501 break;
1502 }
1503 case ltMAKETITLE:
1504 {
1505 if (start && DocumentTitle && DocumentAuthor)
1506 {
1507 // Add a special label for the contents page.
1508 // TexOutput("<CENTER>\n");
1509 TexOutput("<A NAME=\"contents\">");
1510 TexOutput("<H2 ALIGN=CENTER>\n");
1511 TraverseChildrenFromChunk(DocumentTitle);
1512 TexOutput("</H2>");
1513 TexOutput("<P>");
1514 TexOutput("</A>\n");
1515 TexOutput("<P>\n\n");
1516 TexOutput("<H3 ALIGN=CENTER>");
1517 TraverseChildrenFromChunk(DocumentAuthor);
1518 TexOutput("</H3><P>\n\n");
1519 if (DocumentDate)
1520 {
1521 TexOutput("<H3 ALIGN=CENTER>");
1522 TraverseChildrenFromChunk(DocumentDate);
1523 TexOutput("</H3><P>\n\n");
1524 }
1525 // TexOutput("\n</CENTER>\n");
1526 TexOutput("\n<P><HR><P>\n");
1527
1528 /*
1529 // Now do optional frame contents page
1530 if (htmlFrameContents && FrameContents)
1531 {
1532 SetCurrentOutput(FrameContents);
1533
1534 // Add a special label for the contents page.
1535 TexOutput("<CENTER>\n");
1536 TexOutput("<H3>\n");
1537 TraverseChildrenFromChunk(DocumentTitle);
1538 TexOutput("</H3>");
1539 TexOutput("<P>");
1540 TexOutput("</A>\n");
1541 TexOutput("<P>\n\n");
1542 TexOutput("<H3>");
1543 TraverseChildrenFromChunk(DocumentAuthor);
1544 TexOutput("</H3><P>\n\n");
1545 if (DocumentDate)
1546 {
1547 TexOutput("<H4>");
1548 TraverseChildrenFromChunk(DocumentDate);
1549 TexOutput("</H4><P>\n\n");
1550 }
1551 TexOutput("\n</CENTER>\n");
1552 TexOutput("<P><HR><P>\n");
1553
1554 SetCurrentOutput(Titlepage);
1555 }
1556 */
1557 }
1558 break;
1559 }
1560 case ltHELPREF:
1561 case ltHELPREFN:
1562 case ltPOPREF:
1563 case ltURLREF:
1564 {
1565 if (start)
1566 {
1567 helpRefFilename = NULL;
1568 helpRefText = NULL;
1569 }
1570 break;
1571 }
1572 case ltBIBLIOGRAPHY:
1573 {
1574 if (start)
1575 {
1576 DefaultOnMacro(macroId, no_args, start);
1577 }
1578 else
1579 {
1580 DefaultOnMacro(macroId, no_args, start);
1581 TexOutput("</DL>\n");
1582 }
1583 break;
1584 }
1585 case ltHRULE:
1586 {
1587 if (start)
1588 {
1589 TexOutput("<HR>\n");
1590 }
1591 break;
1592 }
1593 case ltRULE:
1594 {
1595 if (start)
1596 {
1597 TexOutput("<HR>\n");
1598 }
1599 break;
1600 }
1601 case ltTABLEOFCONTENTS:
1602 {
1603 if (start)
1604 {
1605 FILE *fd = fopen(ContentsName, "r");
1606 if (fd)
1607 {
1608 int ch = getc(fd);
1609 while (ch != EOF)
1610 {
1611 putc(ch, Titlepage);
1612 ch = getc(fd);
1613 }
1614 fclose(fd);
1615 }
1616 else
1617 {
1618 TexOutput("RUN TEX2RTF AGAIN FOR CONTENTS PAGE\n");
1619 OnInform("Run Tex2RTF again to include contents page.");
1620 }
1621 }
1622 break;
1623 }
1624 case ltLANGLEBRA:
1625 {
1626 if (start)
1627 TexOutput("&lt;");
1628 break;
1629 }
1630 case ltRANGLEBRA:
1631 {
1632 if (start)
1633 TexOutput("&gt;");
1634 break;
1635 }
1636 case ltQUOTE:
1637 case ltQUOTATION:
1638 {
1639 if (start)
1640 TexOutput("<BLOCKQUOTE>");
1641 else
1642 TexOutput("</BLOCKQUOTE>");
1643 break;
1644 }
1645 case ltCAPTION:
1646 case ltCAPTIONSTAR:
1647 {
1648 if (start)
1649 {
1650 if (inTabular)
1651 TexOutput("\n<CAPTION>");
1652
1653 char figBuf[40];
1654
1655 if ( inFigure )
1656 {
1657 figureNo ++;
1658
1659 if (DocumentStyle != LATEX_ARTICLE)
1660 sprintf(figBuf, "%s %d.%d: ", FigureNameString, chapterNo, figureNo);
1661 else
1662 sprintf(figBuf, "%s %d: ", FigureNameString, figureNo);
1663 }
1664 else
1665 {
1666 tableNo ++;
1667
1668 if (DocumentStyle != LATEX_ARTICLE)
1669 sprintf(figBuf, "%s %d.%d: ", TableNameString, chapterNo, tableNo);
1670 else
1671 sprintf(figBuf, "%s %d: ", TableNameString, tableNo);
1672 }
1673
1674 TexOutput(figBuf);
1675 }
1676 else
1677 {
1678 if (inTabular)
1679 TexOutput("\n</CAPTION>\n");
1680
1681 char *topicName = FindTopicName(GetNextChunk());
1682
1683 int n = inFigure ? figureNo : tableNo;
1684
1685 AddTexRef(topicName, NULL, NULL,
1686 ((DocumentStyle != LATEX_ARTICLE) ? chapterNo : n),
1687 ((DocumentStyle != LATEX_ARTICLE) ? n : 0));
1688 }
1689 break;
1690 }
1691 case ltSS:
1692 {
1693 if (start) TexOutput("&szlig;");
1694 break;
1695 }
1696 case ltFIGURE:
1697 {
1698 if (start) inFigure = TRUE;
1699 else inFigure = FALSE;
1700 break;
1701 }
1702 case ltTABLE:
1703 {
1704 if (start) inTable = TRUE;
1705 else inTable = FALSE;
1706 break;
1707 }
1708 default:
1709 DefaultOnMacro(macroId, no_args, start);
1710 break;
1711 }
1712 }
1713
1714 // Called on start/end of argument examination
1715 bool HTMLOnArgument(int macroId, int arg_no, bool start)
1716 {
1717 switch (macroId)
1718 {
1719 case ltCHAPTER:
1720 case ltCHAPTERSTAR:
1721 case ltCHAPTERHEADING:
1722 case ltSECTION:
1723 case ltSECTIONSTAR:
1724 case ltSECTIONHEADING:
1725 case ltSUBSECTION:
1726 case ltSUBSECTIONSTAR:
1727 case ltSUBSUBSECTION:
1728 case ltSUBSUBSECTIONSTAR:
1729 case ltGLOSS:
1730 case ltMEMBERSECTION:
1731 case ltFUNCTIONSECTION:
1732 {
1733 if (!start && (arg_no == 1))
1734 currentSection = GetArgChunk();
1735 return FALSE;
1736 break;
1737 }
1738 case ltFUNC:
1739 {
1740 if (start && (arg_no == 1))
1741 TexOutput("<B>");
1742
1743 if (!start && (arg_no == 1))
1744 TexOutput("</B> ");
1745
1746 if (start && (arg_no == 2))
1747 {
1748 if (!suppressNameDecoration) TexOutput("<B>");
1749 currentMember = GetArgChunk();
1750 }
1751 if (!start && (arg_no == 2))
1752 {
1753 if (!suppressNameDecoration) TexOutput("</B>");
1754 }
1755
1756 if (start && (arg_no == 3))
1757 TexOutput("(");
1758 if (!start && (arg_no == 3))
1759 TexOutput(")");
1760 break;
1761 }
1762 case ltCLIPSFUNC:
1763 {
1764 if (start && (arg_no == 1))
1765 TexOutput("<B>");
1766 if (!start && (arg_no == 1))
1767 TexOutput("</B> ");
1768
1769 if (start && (arg_no == 2))
1770 {
1771 if (!suppressNameDecoration) TexOutput("( ");
1772 currentMember = GetArgChunk();
1773 }
1774 if (!start && (arg_no == 2))
1775 {
1776 }
1777
1778 if (!start && (arg_no == 3))
1779 TexOutput(")");
1780 break;
1781 }
1782 case ltPFUNC:
1783 {
1784 if (!start && (arg_no == 1))
1785 TexOutput(" ");
1786
1787 if (start && (arg_no == 2))
1788 TexOutput("(*");
1789 if (!start && (arg_no == 2))
1790 TexOutput(")");
1791
1792 if (start && (arg_no == 2))
1793 currentMember = GetArgChunk();
1794
1795 if (start && (arg_no == 3))
1796 TexOutput("(");
1797 if (!start && (arg_no == 3))
1798 TexOutput(")");
1799 break;
1800 }
1801 case ltPARAM:
1802 {
1803 if (start && (arg_no == 1))
1804 TexOutput("<B>");
1805 if (!start && (arg_no == 1))
1806 TexOutput("</B>");
1807 if (start && (arg_no == 2))
1808 {
1809 TexOutput("<I>");
1810 }
1811 if (!start && (arg_no == 2))
1812 {
1813 TexOutput("</I>");
1814 }
1815 break;
1816 }
1817 case ltCPARAM:
1818 {
1819 if (start && (arg_no == 1))
1820 TexOutput("<B>");
1821 if (!start && (arg_no == 1))
1822 TexOutput("</B> "); // This is the difference from param - one space!
1823 if (start && (arg_no == 2))
1824 {
1825 TexOutput("<I>");
1826 }
1827 if (!start && (arg_no == 2))
1828 {
1829 TexOutput("</I>");
1830 }
1831 break;
1832 }
1833 case ltMEMBER:
1834 {
1835 if (!start && (arg_no == 1))
1836 TexOutput(" ");
1837
1838 if (start && (arg_no == 2))
1839 currentMember = GetArgChunk();
1840 break;
1841 }
1842 case ltREF:
1843 {
1844 if (start)
1845 {
1846 char *sec = NULL;
1847
1848 char *refName = GetArgData();
1849 if (refName)
1850 {
1851 TexRef *texRef = FindReference(refName);
1852 if (texRef)
1853 {
1854 sec = texRef->sectionNumber;
1855 }
1856 }
1857 if (sec)
1858 {
1859 TexOutput(sec);
1860 }
1861 return FALSE;
1862 }
1863 break;
1864 }
1865 case ltURLREF:
1866 {
1867 if (IsArgOptional())
1868 return FALSE;
1869 else if ((GetNoArgs() - arg_no) == 1)
1870 {
1871 if (start)
1872 helpRefText = GetArgChunk();
1873 return FALSE;
1874 }
1875 else if ((GetNoArgs() - arg_no) == 0) // Arg = 2, or 3 if first is optional
1876 {
1877 if (start)
1878 {
1879 TexChunk *ref = GetArgChunk();
1880 TexOutput("<A HREF=\"");
1881 inVerbatim = TRUE;
1882 TraverseChildrenFromChunk(ref);
1883 inVerbatim = FALSE;
1884 TexOutput("\">");
1885 if (helpRefText)
1886 TraverseChildrenFromChunk(helpRefText);
1887 TexOutput("</A>");
1888 }
1889 return FALSE;
1890 }
1891 break;
1892 }
1893 case ltHELPREF:
1894 case ltHELPREFN:
1895 case ltPOPREF:
1896 {
1897 if (IsArgOptional())
1898 {
1899 if (start)
1900 helpRefFilename = GetArgChunk();
1901 return FALSE;
1902 }
1903 if ((GetNoArgs() - arg_no) == 1)
1904 {
1905 if (start)
1906 helpRefText = GetArgChunk();
1907 return FALSE;
1908 }
1909 else if ((GetNoArgs() - arg_no) == 0) // Arg = 2, or 3 if first is optional
1910 {
1911 if (start)
1912 {
1913 char *refName = GetArgData();
1914 char *refFilename = NULL;
1915
1916 if (refName)
1917 {
1918 TexRef *texRef = FindReference(refName);
1919 if (texRef)
1920 {
1921 if (texRef->refFile && strcmp(texRef->refFile, "??") != 0)
1922 refFilename = texRef->refFile;
1923
1924 TexOutput("<A HREF=\"");
1925 // If a filename is supplied, use it, otherwise try to
1926 // use the filename associated with the reference (from this document).
1927 if (helpRefFilename)
1928 {
1929 TraverseChildrenFromChunk(helpRefFilename);
1930 TexOutput("#");
1931 }
1932 else if (refFilename)
1933 {
1934 TexOutput(ConvertCase(refFilename));
1935 TexOutput("#");
1936 }
1937 TexOutput(refName);
1938 TexOutput("\">");
1939 if (helpRefText)
1940 TraverseChildrenFromChunk(helpRefText);
1941 TexOutput("</A>");
1942 }
1943 else
1944 {
1945 if (helpRefText)
1946 TraverseChildrenFromChunk(helpRefText);
1947 if (!ignoreBadRefs)
1948 TexOutput(" (REF NOT FOUND)");
1949 wxString errBuf;
1950 errBuf.Printf("Warning: unresolved reference '%s'", refName);
1951 OnInform((char *)errBuf.c_str());
1952 }
1953 }
1954 else TexOutput("??");
1955 }
1956 return FALSE;
1957 }
1958 break;
1959 }
1960 case ltIMAGE:
1961 case ltIMAGEL:
1962 case ltIMAGER:
1963 case ltPSBOXTO:
1964 {
1965 if (arg_no == 2)
1966 {
1967 if (start)
1968 {
1969 char *alignment = "";
1970 if (macroId == ltIMAGEL)
1971 alignment = " align=left";
1972 else if (macroId == ltIMAGER)
1973 alignment = " align=right";
1974
1975 // Try to find an XBM or GIF image first.
1976 char *filename = copystring(GetArgData());
1977 char buf[500];
1978
1979 strcpy(buf, filename);
1980 StripExtension(buf);
1981 strcat(buf, ".xbm");
1982 wxString f = TexPathList.FindValidPath(buf);
1983
1984 if (f == "") // Try for a GIF instead
1985 {
1986 strcpy(buf, filename);
1987 StripExtension(buf);
1988 strcat(buf, ".gif");
1989 f = TexPathList.FindValidPath(buf);
1990 }
1991
1992 if (f == "") // Try for a JPEG instead
1993 {
1994 strcpy(buf, filename);
1995 StripExtension(buf);
1996 strcat(buf, ".jpg");
1997 f = TexPathList.FindValidPath(buf);
1998 }
1999
2000 if (f == "") // Try for a PNG instead
2001 {
2002 strcpy(buf, filename);
2003 StripExtension(buf);
2004 strcat(buf, ".png");
2005 f = TexPathList.FindValidPath(buf);
2006 }
2007
2008 if (f != "")
2009 {
2010 char *inlineFilename = copystring(f);
2011 #if 0
2012 char *originalFilename = TexPathList.FindValidPath(filename);
2013 // If we have found the existing filename, make the inline
2014 // image point to the original file (could be PS, for example)
2015 if (originalFilename && (strcmp(inlineFilename, originalFilename) != 0))
2016 {
2017 TexOutput("<A HREF=\"");
2018 TexOutput(ConvertCase(originalFilename));
2019 TexOutput("\">");
2020 TexOutput("<img src=\"");
2021 TexOutput(ConvertCase(wxFileNameFromPath(inlineFilename)));
2022 TexOutput("\""); TexOutput(alignment); TexOutput("></A>");
2023 }
2024 else
2025 #endif
2026 {
2027 TexOutput("<img src=\"");
2028 TexOutput(ConvertCase(wxFileNameFromPath(inlineFilename)));
2029 TexOutput("\""); TexOutput(alignment); TexOutput("></A>");
2030 delete[] inlineFilename;
2031 }
2032 }
2033 else
2034 {
2035 // Last resort - a link to a PS file.
2036 TexOutput("<A HREF=\"");
2037 TexOutput(ConvertCase(wxFileNameFromPath(filename)));
2038 TexOutput("\">Picture</A>\n");
2039 sprintf(buf, "Warning: could not find an inline XBM/GIF for %s.", filename);
2040 OnInform(buf);
2041 }
2042 }
2043 }
2044 return FALSE;
2045 break;
2046 }
2047 // First arg is PSBOX spec (ignored), second is image file, third is map name.
2048 case ltIMAGEMAP:
2049 {
2050 static char *imageFile = NULL;
2051 if (start && (arg_no == 2))
2052 {
2053 // Try to find an XBM or GIF image first.
2054 char *filename = copystring(GetArgData());
2055 char buf[500];
2056
2057 strcpy(buf, filename);
2058 StripExtension(buf);
2059 strcat(buf, ".xbm");
2060 wxString f = TexPathList.FindValidPath(buf);
2061
2062 if (f == "") // Try for a GIF instead
2063 {
2064 strcpy(buf, filename);
2065 StripExtension(buf);
2066 strcat(buf, ".gif");
2067 f = TexPathList.FindValidPath(buf);
2068 }
2069 if (f == "")
2070 {
2071 char buf[300];
2072 sprintf(buf, "Warning: could not find an inline XBM/GIF for %s.", filename);
2073 OnInform(buf);
2074 }
2075 delete[] filename;
2076 if (imageFile)
2077 delete[] imageFile;
2078 imageFile = NULL;
2079 if (!f.IsEmpty())
2080 {
2081 imageFile = copystring(f);
2082 }
2083 }
2084 else if (start && (arg_no == 3))
2085 {
2086 if (imageFile)
2087 {
2088 // First, try to find a .shg (segmented hypergraphics file)
2089 // that we can convert to a map file
2090 char buf[256];
2091 strcpy(buf, imageFile);
2092 StripExtension(buf);
2093 strcat(buf, ".shg");
2094 wxString f = TexPathList.FindValidPath(buf);
2095
2096 if (f != "")
2097 {
2098 // The default HTML file to go to is THIS file (so a no-op)
2099 SHGToMap((char*) (const char*) f, currentFileName);
2100 }
2101
2102 char *mapName = GetArgData();
2103 TexOutput("<A HREF=\"/cgi-bin/imagemap/");
2104 if (mapName)
2105 TexOutput(mapName);
2106 else
2107 TexOutput("unknown");
2108 TexOutput("\">");
2109 TexOutput("<img src=\"");
2110 TexOutput(ConvertCase(wxFileNameFromPath(imageFile)));
2111 TexOutput("\" ISMAP></A><P>");
2112 delete[] imageFile;
2113 imageFile = NULL;
2114 }
2115 }
2116 return FALSE;
2117 break;
2118 }
2119 case ltINDENTED :
2120 {
2121 if ( arg_no == 1 )
2122 return FALSE;
2123 else
2124 {
2125 return TRUE;
2126 }
2127 }
2128 case ltITEM:
2129 {
2130 if (start)
2131 {
2132 descriptionItemArg = GetArgChunk();
2133 return FALSE;
2134 }
2135 return TRUE;
2136 }
2137 case ltTWOCOLITEM:
2138 case ltTWOCOLITEMRULED:
2139 {
2140 /*
2141 if (start && (arg_no == 1))
2142 TexOutput("\n<DT> ");
2143 if (start && (arg_no == 2))
2144 TexOutput("<DD> ");
2145 */
2146 if (arg_no == 1)
2147 {
2148 if ( start ) {
2149 // DHS
2150 if (TwoColWidthA > -1) {
2151 char buf[100];
2152 sprintf(buf,"\n<TR><TD VALIGN=TOP WIDTH=%d>\n",TwoColWidthA);
2153 TexOutput(buf);
2154 } else
2155 TexOutput("\n<TR><TD VALIGN=TOP>\n");
2156 OutputFont();
2157 } else
2158 TexOutput("\n</FONT></TD>\n");
2159 }
2160 if (arg_no == 2)
2161 {
2162 // DHS
2163 if ( start ) {
2164 if (TwoColWidthB > -1) {
2165 char buf[100];
2166 sprintf(buf,"\n<TD VALIGN=TOP WIDTH=%d>\n",TwoColWidthB);
2167 TexOutput(buf);
2168 } else
2169 TexOutput("\n<TD VALIGN=TOP>\n");
2170 OutputFont();
2171 } else
2172 TexOutput("\n</FONT></TD></TR>\n");
2173 }
2174 return TRUE;
2175 break;
2176 }
2177 case ltNUMBEREDBIBITEM:
2178 {
2179 if (arg_no == 1 && start)
2180 {
2181 TexOutput("\n<DT> ");
2182 }
2183 if (arg_no == 2 && !start)
2184 TexOutput("<P>\n");
2185 break;
2186 }
2187 case ltBIBITEM:
2188 {
2189 char buf[100];
2190 if (arg_no == 1 && start)
2191 {
2192 char *citeKey = GetArgData();
2193 TexRef *ref = (TexRef *)TexReferences.Get(citeKey);
2194 if (ref)
2195 {
2196 if (ref->sectionNumber) delete[] ref->sectionNumber;
2197 sprintf(buf, "[%d]", citeCount);
2198 ref->sectionNumber = copystring(buf);
2199 }
2200
2201 sprintf(buf, "\n<DT> [%d] ", citeCount);
2202 TexOutput(buf);
2203 citeCount ++;
2204 return FALSE;
2205 }
2206 if (arg_no == 2 && !start)
2207 TexOutput("<P>\n");
2208 return TRUE;
2209 break;
2210 }
2211 case ltMARGINPAR:
2212 case ltMARGINPARODD:
2213 case ltMARGINPAREVEN:
2214 case ltNORMALBOX:
2215 case ltNORMALBOXD:
2216 {
2217 if (start)
2218 {
2219 TexOutput("<HR>\n");
2220 return TRUE;
2221 }
2222 else
2223 TexOutput("<HR><P>\n");
2224 break;
2225 }
2226 // DHS
2227 case ltTWOCOLWIDTHA:
2228 {
2229 if (start)
2230 {
2231 char *val = GetArgData();
2232 float points = ParseUnitArgument(val);
2233 TwoColWidthA = (int)((points * 100.0) / 72.0);
2234 }
2235 return FALSE;
2236 break;
2237 }
2238 // DHS
2239 case ltTWOCOLWIDTHB:
2240 {
2241 if (start)
2242 {
2243 char *val = GetArgData();
2244 float points = ParseUnitArgument(val);
2245 TwoColWidthB = (int)((points * 100.0) / 72.0);
2246 }
2247 return FALSE;
2248 break;
2249 }
2250 /*
2251 * Accents
2252 *
2253 */
2254 case ltACCENT_GRAVE:
2255 {
2256 if (start)
2257 {
2258 char *val = GetArgData();
2259 if (val)
2260 {
2261 switch (val[0])
2262 {
2263 case 'a':
2264 TexOutput("&agrave;");
2265 break;
2266 case 'e':
2267 TexOutput("&egrave;");
2268 break;
2269 case 'i':
2270 TexOutput("&igrave;");
2271 break;
2272 case 'o':
2273 TexOutput("&ograve;");
2274 break;
2275 case 'u':
2276 TexOutput("&ugrave;");
2277 break;
2278 case 'A':
2279 TexOutput("&Agrave;");
2280 break;
2281 case 'E':
2282 TexOutput("&Egrave;");
2283 break;
2284 case 'I':
2285 TexOutput("&Igrave;");
2286 break;
2287 case 'O':
2288 TexOutput("&Ograve;");
2289 break;
2290 case 'U':
2291 TexOutput("&Igrave;");
2292 break;
2293 default:
2294 break;
2295 }
2296 }
2297 }
2298 return FALSE;
2299 break;
2300 }
2301 case ltACCENT_ACUTE:
2302 {
2303 if (start)
2304 {
2305 char *val = GetArgData();
2306 if (val)
2307 {
2308 switch (val[0])
2309 {
2310 case 'a':
2311 TexOutput("&aacute;");
2312 break;
2313 case 'e':
2314 TexOutput("&eacute;");
2315 break;
2316 case 'i':
2317 TexOutput("&iacute;");
2318 break;
2319 case 'o':
2320 TexOutput("&oacute;");
2321 break;
2322 case 'u':
2323 TexOutput("&uacute;");
2324 break;
2325 case 'y':
2326 TexOutput("&yacute;");
2327 break;
2328 case 'A':
2329 TexOutput("&Aacute;");
2330 break;
2331 case 'E':
2332 TexOutput("&Eacute;");
2333 break;
2334 case 'I':
2335 TexOutput("&Iacute;");
2336 break;
2337 case 'O':
2338 TexOutput("&Oacute;");
2339 break;
2340 case 'U':
2341 TexOutput("&Uacute;");
2342 break;
2343 case 'Y':
2344 TexOutput("&Yacute;");
2345 break;
2346 default:
2347 break;
2348 }
2349 }
2350 }
2351 return FALSE;
2352 break;
2353 }
2354 case ltACCENT_CARET:
2355 {
2356 if (start)
2357 {
2358 char *val = GetArgData();
2359 if (val)
2360 {
2361 switch (val[0])
2362 {
2363 case 'a':
2364 TexOutput("&acirc;");
2365 break;
2366 case 'e':
2367 TexOutput("&ecirc;");
2368 break;
2369 case 'i':
2370 TexOutput("&icirc;");
2371 break;
2372 case 'o':
2373 TexOutput("&ocirc;");
2374 break;
2375 case 'u':
2376 TexOutput("&ucirc;");
2377 break;
2378 case 'A':
2379 TexOutput("&Acirc;");
2380 break;
2381 case 'E':
2382 TexOutput("&Ecirc;");
2383 break;
2384 case 'I':
2385 TexOutput("&Icirc;");
2386 break;
2387 case 'O':
2388 TexOutput("&Ocirc;");
2389 break;
2390 case 'U':
2391 TexOutput("&Icirc;");
2392 break;
2393 default:
2394 break;
2395 }
2396 }
2397 }
2398 return FALSE;
2399 break;
2400 }
2401 case ltACCENT_TILDE:
2402 {
2403 if (start)
2404 {
2405 char *val = GetArgData();
2406 if (val)
2407 {
2408 switch (val[0])
2409 {
2410 case ' ':
2411 TexOutput("~");
2412 break;
2413 case 'a':
2414 TexOutput("&atilde;");
2415 break;
2416 case 'n':
2417 TexOutput("&ntilde;");
2418 break;
2419 case 'o':
2420 TexOutput("&otilde;");
2421 break;
2422 case 'A':
2423 TexOutput("&Atilde;");
2424 break;
2425 case 'N':
2426 TexOutput("&Ntilde;");
2427 break;
2428 case 'O':
2429 TexOutput("&Otilde;");
2430 break;
2431 default:
2432 break;
2433 }
2434 }
2435 }
2436 return FALSE;
2437 break;
2438 }
2439 case ltACCENT_UMLAUT:
2440 {
2441 if (start)
2442 {
2443 char *val = GetArgData();
2444 if (val)
2445 {
2446 switch (val[0])
2447 {
2448 case 'a':
2449 TexOutput("&auml;");
2450 break;
2451 case 'e':
2452 TexOutput("&euml;");
2453 break;
2454 case 'i':
2455 TexOutput("&iuml;");
2456 break;
2457 case 'o':
2458 TexOutput("&ouml;");
2459 break;
2460 case 'u':
2461 TexOutput("&uuml;");
2462 break;
2463 case 'y':
2464 TexOutput("&yuml;");
2465 break;
2466 case 'A':
2467 TexOutput("&Auml;");
2468 break;
2469 case 'E':
2470 TexOutput("&Euml;");
2471 break;
2472 case 'I':
2473 TexOutput("&Iuml;");
2474 break;
2475 case 'O':
2476 TexOutput("&Ouml;");
2477 break;
2478 case 'U':
2479 TexOutput("&Uuml;");
2480 break;
2481 case 'Y':
2482 TexOutput("&Yuml;");
2483 break;
2484 default:
2485 break;
2486 }
2487 }
2488 }
2489 return FALSE;
2490 break;
2491 }
2492 case ltACCENT_DOT:
2493 {
2494 if (start)
2495 {
2496 char *val = GetArgData();
2497 if (val)
2498 {
2499 switch (val[0])
2500 {
2501 case 'a':
2502 TexOutput("&aring;");
2503 break;
2504 case 'A':
2505 TexOutput("&Aring;");
2506 break;
2507 default:
2508 break;
2509 }
2510 }
2511 }
2512 return FALSE;
2513 break;
2514 }
2515 case ltBACKGROUND:
2516 {
2517 if (start)
2518 {
2519 char *val = GetArgData();
2520 if (val)
2521 {
2522 bool isPicture = FALSE;
2523 char *s = ParseColourString(val, &isPicture);
2524 if (isPicture)
2525 {
2526 if (backgroundImageString)
2527 delete[] backgroundImageString;
2528 backgroundImageString = copystring(val);
2529 }
2530 else
2531 {
2532 if (backgroundColourString)
2533 delete[] backgroundColourString;
2534 backgroundColourString = copystring(val);
2535 }
2536 }
2537 }
2538 return FALSE;
2539 break;
2540 }
2541 case ltBACKGROUNDIMAGE:
2542 {
2543 if (start)
2544 {
2545 char *val = GetArgData();
2546 if (val)
2547 {
2548 if (backgroundImageString)
2549 delete[] backgroundImageString;
2550 backgroundImageString = copystring(val);
2551 }
2552 }
2553 return FALSE;
2554 break;
2555 }
2556 case ltBACKGROUNDCOLOUR:
2557 {
2558 if (start)
2559 {
2560 char *val = GetArgData();
2561 if (val)
2562 {
2563 if (backgroundColourString)
2564 delete[] backgroundColourString;
2565 backgroundColourString = copystring(val);
2566 }
2567 }
2568 return FALSE;
2569 break;
2570 }
2571 case ltTEXTCOLOUR:
2572 {
2573 if (start)
2574 {
2575 char *val = GetArgData();
2576 if (val)
2577 {
2578 if (textColourString)
2579 delete[] textColourString;
2580 textColourString = copystring(val);
2581 }
2582 }
2583 return FALSE;
2584 break;
2585 }
2586 case ltLINKCOLOUR:
2587 {
2588 if (start)
2589 {
2590 char *val = GetArgData();
2591 if (val)
2592 {
2593 if (linkColourString)
2594 delete[] linkColourString;
2595 linkColourString = copystring(val);
2596 }
2597 }
2598 return FALSE;
2599 break;
2600 }
2601 case ltFOLLOWEDLINKCOLOUR:
2602 {
2603 if (start)
2604 {
2605 char *val = GetArgData();
2606 if (val)
2607 {
2608 if (followedLinkColourString)
2609 delete[] followedLinkColourString;
2610 followedLinkColourString = copystring(val);
2611 }
2612 }
2613 return FALSE;
2614 break;
2615 }
2616 case ltACCENT_CADILLA:
2617 {
2618 if (start)
2619 {
2620 char *val = GetArgData();
2621 if (val)
2622 {
2623 switch (val[0])
2624 {
2625 case 'c':
2626 TexOutput("&ccedil;");
2627 break;
2628 case 'C':
2629 TexOutput("&Ccedil;");
2630 break;
2631 default:
2632 break;
2633 }
2634 }
2635 }
2636 return FALSE;
2637 break;
2638 }
2639 /*
2640 case ltFOOTNOTE:
2641 case ltFOOTNOTEPOPUP:
2642 {
2643 if (arg_no == 1)
2644 return TRUE;
2645 else
2646 return FALSE;
2647 break;
2648 }
2649 */
2650 case ltTABULAR:
2651 case ltSUPERTABULAR:
2652 {
2653 if (arg_no == 1)
2654 {
2655 if (start)
2656 {
2657 currentRowNumber = 0;
2658 inTabular = TRUE;
2659 startRows = TRUE;
2660 tableVerticalLineLeft = FALSE;
2661 tableVerticalLineRight = FALSE;
2662 int currentWidth = 0;
2663
2664 char *alignString = copystring(GetArgData());
2665 ParseTableArgument(alignString);
2666
2667 TexOutput("<TABLE BORDER>\n");
2668
2669 // Write the first row formatting for compatibility
2670 // with standard Latex
2671 if (compatibilityMode)
2672 {
2673 TexOutput("<TR>\n<TD>");
2674 OutputFont();
2675 /*
2676 for (int i = 0; i < noColumns; i++)
2677 {
2678 currentWidth += TableData[i].width;
2679 sprintf(buf, "\\cellx%d", currentWidth);
2680 TexOutput(buf);
2681 }
2682 TexOutput("\\pard\\intbl\n");
2683 */
2684 }
2685 delete[] alignString;
2686
2687 return FALSE;
2688 }
2689 }
2690 else if (arg_no == 2 && !start)
2691 {
2692 TexOutput("</TABLE>\n");
2693 inTabular = FALSE;
2694 }
2695 break;
2696 }
2697 case ltTHEBIBLIOGRAPHY:
2698 {
2699 if (start && (arg_no == 1))
2700 {
2701 ReopenFile(&Chapters, &ChaptersName);
2702 AddTexRef("bibliography", ChaptersName, "bibliography");
2703 SetCurrentSubsectionName("bibliography", ChaptersName);
2704
2705 citeCount = 1;
2706
2707 SetCurrentOutput(Chapters);
2708
2709 char titleBuf[150];
2710 if (truncateFilenames)
2711 sprintf(titleBuf, "%s.htm", FileNameFromPath(FileRoot));
2712 else
2713 sprintf(titleBuf, "%s_contents.html", FileNameFromPath(FileRoot));
2714
2715 HTMLHead();
2716 TexOutput("<title>");
2717 TexOutput(ReferencesNameString);
2718 TexOutput("</title></head>\n");
2719 OutputBodyStart();
2720
2721 fprintf(Chapters, "<A NAME=\"%s\">\n<H2>%s", "bibliography", ReferencesNameString);
2722 AddBrowseButtons("contents", titleBuf, // Up
2723 lastTopic, lastFileName, // Last topic
2724 "bibliography", ChaptersName); // This topic
2725
2726 SetCurrentOutputs(Contents, Chapters);
2727 fprintf(Contents, "\n<LI><A HREF=\"%s#%s\">", ConvertCase(ChaptersName), "bibliography");
2728
2729 fprintf(Contents, "%s</A>\n", ReferencesNameString);
2730 fprintf(Chapters, "</H2>\n</A>\n");
2731
2732 SetCurrentOutput(Chapters);
2733 return FALSE;
2734 }
2735 if (!start && (arg_no == 2))
2736 {
2737 }
2738 return TRUE;
2739 break;
2740 }
2741 case ltINDEX:
2742 {
2743 /* Build up list of keywords associated with topics */
2744 if (start)
2745 {
2746 // char *entry = GetArgData();
2747 char buf[300];
2748 OutputChunkToString(GetArgChunk(), buf);
2749 if (CurrentTopic)
2750 {
2751 AddKeyWordForTopic(CurrentTopic, buf, currentFileName);
2752 }
2753 }
2754 return FALSE;
2755 break;
2756 }
2757 case ltFCOL:
2758 // case ltBCOL:
2759 {
2760 if (start)
2761 {
2762 switch (arg_no)
2763 {
2764 case 1:
2765 {
2766 char *name = GetArgData();
2767 char buf2[10];
2768 if (!FindColourHTMLString(name, buf2))
2769 {
2770 strcpy(buf2, "#000000");
2771 char buf[100];
2772 sprintf(buf, "Could not find colour name %s", name);
2773 OnError(buf);
2774 }
2775 TexOutput("<FONT COLOR=\"");
2776 TexOutput(buf2);
2777 TexOutput("\">");
2778 break;
2779 }
2780 case 2:
2781 {
2782 return TRUE;
2783 break;
2784 }
2785 default:
2786 break;
2787 }
2788 }
2789 else
2790 {
2791 if (arg_no == 2) TexOutput("</FONT>");
2792 }
2793 return FALSE;
2794 break;
2795 }
2796 case ltINSERTATLEVEL:
2797 {
2798 // This macro allows you to insert text at a different level
2799 // from the current level, e.g. into the Sections from within a subsubsection.
2800 if (useWord)
2801 return FALSE;
2802 static int currentLevelNo = 1;
2803 static FILE* oldLevelFile = Chapters;
2804 if (start)
2805 {
2806 switch (arg_no)
2807 {
2808 case 1:
2809 {
2810 oldLevelFile = CurrentOutput1;
2811
2812 char *str = GetArgData();
2813 currentLevelNo = atoi(str);
2814 FILE* outputFile;
2815 // TODO: cope with article style (no chapters)
2816 switch (currentLevelNo)
2817 {
2818 case 1:
2819 {
2820 outputFile = Chapters;
2821 break;
2822 }
2823 case 2:
2824 {
2825 outputFile = Sections;
2826 break;
2827 }
2828 case 3:
2829 {
2830 outputFile = Subsections;
2831 break;
2832 }
2833 case 4:
2834 {
2835 outputFile = Subsubsections;
2836 break;
2837 }
2838 default:
2839 {
2840 outputFile = NULL;
2841 break;
2842 }
2843 }
2844 if (outputFile)
2845 CurrentOutput1 = outputFile;
2846 return FALSE;
2847 break;
2848 }
2849 case 2:
2850 {
2851 return TRUE;
2852 break;
2853 }
2854 default:
2855 break;
2856 }
2857 return TRUE;
2858 }
2859 else
2860 {
2861 if (arg_no == 2)
2862 {
2863 CurrentOutput1 = oldLevelFile;
2864 }
2865 return TRUE;
2866 }
2867 }
2868 default:
2869 return DefaultOnArgument(macroId, arg_no, start);
2870 break;
2871 }
2872 return TRUE;
2873 }
2874
2875 bool HTMLGo(void)
2876 {
2877 fileId = 0;
2878 inVerbatim = FALSE;
2879 indentLevel = 0;
2880 inTabular = FALSE;
2881 startRows = FALSE;
2882 tableVerticalLineLeft = FALSE;
2883 tableVerticalLineRight = FALSE;
2884 noColumns = 0;
2885
2886 if (InputFile && OutputFile)
2887 {
2888 // Do some HTML-specific transformations on all the strings,
2889 // recursively
2890 Text2HTML(GetTopLevelChunk());
2891
2892 char buf[300];
2893 if (truncateFilenames)
2894 sprintf(buf, "%s.htm", FileRoot);
2895 else
2896 sprintf(buf, "%s_contents.html", FileRoot);
2897 if (TitlepageName) delete[] TitlepageName;
2898 TitlepageName = copystring(buf);
2899 Titlepage = fopen(buf, "w");
2900
2901 if (truncateFilenames)
2902 sprintf(buf, "%s_fc.htm", FileRoot);
2903 else
2904 sprintf(buf, "%s_fcontents.html", FileRoot);
2905
2906 contentsFrameName = copystring(buf);
2907
2908 Contents = fopen(TmpContentsName, "w");
2909
2910 if (htmlFrameContents)
2911 {
2912 // FrameContents = fopen(TmpFrameContentsName, "w");
2913 FrameContents = fopen(contentsFrameName, "w");
2914 fprintf(FrameContents, "<HTML>\n<UL>\n");
2915 }
2916
2917 if (!Titlepage || !Contents)
2918 {
2919 OnError("Cannot open output file!");
2920 return FALSE;
2921 }
2922 AddTexRef("contents", FileNameFromPath(TitlepageName), ContentsNameString);
2923
2924 fprintf(Contents, "<P><P><H2>%s</H2><P><P>\n", ContentsNameString);
2925
2926 fprintf(Contents, "<UL>\n");
2927
2928 SetCurrentOutput(Titlepage);
2929 if (htmlWorkshopFiles) HTMLWorkshopStartContents();
2930 OnInform("Converting...");
2931
2932 TraverseDocument();
2933 fprintf(Contents, "</UL>\n\n");
2934
2935 // SetCurrentOutput(Titlepage);
2936 fclose(Titlepage);
2937
2938 if (Contents)
2939 {
2940 // fprintf(Titlepage, "\n</BODY></HTML>\n");
2941 fclose(Contents);
2942 Contents = NULL;
2943 }
2944
2945 if (FrameContents)
2946 {
2947 fprintf(FrameContents, "\n</UL>\n");
2948 fprintf(FrameContents, "</HTML>\n");
2949 fclose(FrameContents);
2950 FrameContents = NULL;
2951 }
2952
2953 if (Chapters)
2954 {
2955 fprintf(Chapters, "\n</FONT></BODY></HTML>\n");
2956 fclose(Chapters);
2957 Chapters = NULL;
2958 }
2959 if (Sections)
2960 {
2961 fprintf(Sections, "\n</FONT></BODY></HTML>\n");
2962 fclose(Sections);
2963 Sections = NULL;
2964 }
2965 if (Subsections && !combineSubSections)
2966 {
2967 fprintf(Subsections, "\n</FONT></BODY></HTML>\n");
2968 fclose(Subsections);
2969 Subsections = NULL;
2970 }
2971 if (Subsubsections && !combineSubSections)
2972 {
2973 fprintf(Subsubsections, "\n</FONT></BODY></HTML>\n");
2974 fclose(Subsubsections);
2975 Subsubsections = NULL;
2976 }
2977 if ( SectionContentsFD )
2978 {
2979 fclose(SectionContentsFD);
2980 SectionContentsFD = NULL;
2981 }
2982
2983 // Create a temporary file for the title page header, add some info,
2984 // and concat the titlepage just generated.
2985 // This is necessary in order to put the title of the document
2986 // at the TOP of the file within <HEAD>, even though we only find out
2987 // what it is later on.
2988 FILE *tmpTitle = fopen("title.tmp", "w");
2989 if (tmpTitle)
2990 {
2991 if (DocumentTitle)
2992 {
2993 SetCurrentOutput(tmpTitle);
2994 HTMLHead();
2995 TexOutput("\n<HEAD><TITLE>");
2996 TraverseChildrenFromChunk(DocumentTitle);
2997 TexOutput("</TITLE></HEAD>\n");
2998 }
2999 else
3000 {
3001 SetCurrentOutput(tmpTitle);
3002 HTMLHeadTo(tmpTitle);
3003 if (contentsString)
3004 fprintf(tmpTitle, "<TITLE>%s</TITLE></HEAD>\n\n", contentsString);
3005 else
3006 fprintf(tmpTitle, "<TITLE>%s</TITLE></HEAD>\n\n", FileNameFromPath(FileRoot));
3007 }
3008
3009 // Output frame information
3010 if (htmlFrameContents)
3011 {
3012 char firstFileName[300];
3013 if (truncateFilenames)
3014 sprintf(firstFileName, "%s1.htm", FileRoot);
3015 else
3016 sprintf(firstFileName, "%s1.html", FileRoot);
3017
3018 fprintf(tmpTitle, "<FRAMESET COLS=\"30%%,70%%\">\n");
3019
3020 fprintf(tmpTitle, "<FRAME SRC=\"%s\">\n", ConvertCase(FileNameFromPath(contentsFrameName)));
3021 fprintf(tmpTitle, "<FRAME SRC=\"%s\" NAME=\"mainwindow\">\n", ConvertCase(FileNameFromPath(firstFileName)));
3022 fprintf(tmpTitle, "</FRAMESET>\n");
3023
3024 fprintf(tmpTitle, "<NOFRAMES>\n");
3025 }
3026
3027 // Output <BODY...> to temporary title page
3028 OutputBodyStart();
3029
3030 // Concat titlepage
3031 FILE *fd = fopen(TitlepageName, "r");
3032 if (fd)
3033 {
3034 int ch = getc(fd);
3035 while (ch != EOF)
3036 {
3037 putc(ch, tmpTitle);
3038 ch = getc(fd);
3039 }
3040 fclose(fd);
3041 }
3042
3043 fprintf(tmpTitle, "\n</FONT></BODY>\n");
3044
3045 if (htmlFrameContents)
3046 {
3047 fprintf(tmpTitle, "\n</NOFRAMES>\n");
3048 }
3049 fprintf(tmpTitle, "\n</HTML>\n");
3050
3051 fclose(tmpTitle);
3052 if (FileExists(TitlepageName)) wxRemoveFile(TitlepageName);
3053 if (!wxRenameFile("title.tmp", TitlepageName))
3054 {
3055 wxCopyFile("title.tmp", TitlepageName);
3056 wxRemoveFile("title.tmp");
3057 }
3058 }
3059
3060 if (lastFileName) delete[] lastFileName;
3061 lastFileName = NULL;
3062 if (lastTopic) delete[] lastTopic;
3063 lastTopic = NULL;
3064
3065 if (FileExists(ContentsName)) wxRemoveFile(ContentsName);
3066
3067 if (!wxRenameFile(TmpContentsName, ContentsName))
3068 {
3069 wxCopyFile(TmpContentsName, ContentsName);
3070 wxRemoveFile(TmpContentsName);
3071 }
3072
3073 // Generate .htx file if requested
3074 if (htmlIndex)
3075 {
3076 char htmlIndexName[300];
3077 sprintf(htmlIndexName, "%s.htx", FileRoot);
3078 GenerateHTMLIndexFile(htmlIndexName);
3079 }
3080
3081 // Generate HTML Help Workshop files if requested
3082 if (htmlWorkshopFiles)
3083 {
3084 HTMLWorkshopEndContents();
3085 GenerateHTMLWorkshopFiles(FileRoot);
3086 }
3087
3088
3089 return TRUE;
3090 }
3091
3092 return FALSE;
3093 }
3094
3095 // Output .htx index file
3096 void GenerateHTMLIndexFile(char *fname)
3097 {
3098 FILE *fd = fopen(fname, "w");
3099 if (!fd)
3100 return;
3101
3102 TopicTable.BeginFind();
3103 wxNode *node = NULL;
3104 while ((node = TopicTable.Next()))
3105 {
3106 TexTopic *texTopic = (TexTopic *)node->Data();
3107 const char *topicName = node->GetKeyString();
3108 if (texTopic->filename && texTopic->keywords)
3109 {
3110 wxNode *node1 = texTopic->keywords->First();
3111 while (node1)
3112 {
3113 char *s = (char *)node1->Data();
3114 fprintf(fd, "%s|%s|%s\n", topicName, texTopic->filename, s);
3115 node1 = node1->Next();
3116 }
3117 }
3118 }
3119 fclose(fd);
3120 }
3121
3122
3123
3124
3125
3126
3127
3128 // output .hpp, .hhc and .hhk files:
3129
3130
3131 void GenerateHTMLWorkshopFiles(char *fname)
3132 {
3133 FILE *f;
3134 char buf[300];
3135
3136 /* Generate project file : */
3137
3138 sprintf(buf, "%s.hhp", fname);
3139 f = fopen(buf, "wt");
3140 fprintf(f,
3141 "[OPTIONS]\n"
3142 "Compatibility=1.1\n"
3143 "Full-text search=Yes\n"
3144 "Contents file=%s.hhc\n"
3145 "Compiled file=%s.chm\n"
3146 "Default Window=%sHelp\n"
3147 "Default topic=%s\n"
3148 "Index file=%s.hhk\n"
3149 "Title=",
3150 FileNameFromPath(fname),
3151 FileNameFromPath(fname),
3152 FileNameFromPath(fname),
3153 FileNameFromPath(TitlepageName),
3154 FileNameFromPath(fname)
3155 );
3156
3157 if (DocumentTitle) {
3158 SetCurrentOutput(f);
3159 TraverseChildrenFromChunk(DocumentTitle);
3160 }
3161 else fprintf(f, "(unknown)");
3162
3163 fprintf(f, "\n\n[WINDOWS]\n"
3164 "%sHelp=,\"%s.hhc\",\"%s.hhk\",\"%s\",,,,,,0x2420,,0x380e,,,,,0,,,",
3165 FileNameFromPath(fname),
3166 FileNameFromPath(fname),
3167 FileNameFromPath(fname),
3168 FileNameFromPath(TitlepageName));
3169
3170
3171 fprintf(f, "\n\n[FILES]\n");
3172 fprintf(f, "%s\n", FileNameFromPath(TitlepageName));
3173 for (int i = 1; i <= fileId; i++) {
3174 if (truncateFilenames)
3175 sprintf(buf, "%s%d.htm", FileNameFromPath(FileRoot), i);
3176 else
3177 sprintf(buf, "%s%d.html", FileNameFromPath(FileRoot), i);
3178 fprintf(f, "%s\n", buf);
3179 }
3180 fclose(f);
3181
3182 /* Generate index file : */
3183
3184 sprintf(buf, "%s.hhk", fname);
3185 f = fopen(buf, "wt");
3186
3187 fprintf(f,
3188 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n"
3189 "<HTML>\n");
3190 HTMLHeadTo(f);
3191 fprintf(f,
3192 "\n"
3193 "<meta name=\"GENERATOR\" content=\"tex2rtf\">\n"
3194 "<!-- Sitemap 1.0 -->\n"
3195 "</HEAD><BODY>\n"
3196 "<OBJECT type=\"text/site properties\">\n"
3197 " <param name=\"ImageType\" value=\"Folder\">\n"
3198 "</OBJECT>\n"
3199 "<UL>\n");
3200
3201 TopicTable.BeginFind();
3202 wxNode *node = NULL;
3203 while ((node = TopicTable.Next()))
3204 {
3205 TexTopic *texTopic = (TexTopic *)node->Data();
3206 const char *topicName = node->GetKeyString();
3207 if (texTopic->filename && texTopic->keywords)
3208 {
3209 wxNode *node1 = texTopic->keywords->First();
3210 while (node1)
3211 {
3212 char *s = (char *)node1->Data();
3213 fprintf(f,
3214 " <LI> <OBJECT type=\"text/sitemap\">\n"
3215 " <param name=\"Local\" value=\"%s#%s\">\n"
3216 " <param name=\"Name\" value=\"%s\">\n"
3217 " </OBJECT>\n",
3218 texTopic->filename, topicName, s);
3219 node1 = node1->Next();
3220 }
3221 }
3222 }
3223
3224 fprintf(f, "</UL>\n");
3225 fclose(f);
3226 }
3227
3228
3229
3230 static FILE *HTMLWorkshopContents = NULL;
3231 static int HTMLWorkshopLastLevel = 0;
3232
3233 void HTMLWorkshopAddToContents(int level, char *s, char *file)
3234 {
3235 int i;
3236
3237 if (level > HTMLWorkshopLastLevel)
3238 for (i = HTMLWorkshopLastLevel; i < level; i++)
3239 fprintf(HTMLWorkshopContents, "<UL>");
3240 if (level < HTMLWorkshopLastLevel)
3241 for (i = level; i < HTMLWorkshopLastLevel; i++)
3242 fprintf(HTMLWorkshopContents, "</UL>");
3243
3244 SetCurrentOutput(HTMLWorkshopContents);
3245 fprintf(HTMLWorkshopContents,
3246 " <LI> <OBJECT type=\"text/sitemap\">\n"
3247 " <param name=\"Local\" value=\"%s#%s\">\n"
3248 " <param name=\"Name\" value=\"",
3249 file, s);
3250 OutputCurrentSection();
3251 fprintf(HTMLWorkshopContents,
3252 "\">\n"
3253 " </OBJECT>\n");
3254 HTMLWorkshopLastLevel = level;
3255 }
3256
3257
3258 void HTMLWorkshopStartContents()
3259 {
3260 char buf[300];
3261 sprintf(buf, "%s.hhc", FileRoot);
3262 HTMLWorkshopContents = fopen(buf, "wt");
3263 HTMLWorkshopLastLevel = 0;
3264
3265 fprintf(HTMLWorkshopContents,
3266 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n"
3267 "<HTML>\n");
3268 HTMLHeadTo(HTMLWorkshopContents);
3269 fprintf(HTMLWorkshopContents,
3270 "\n"
3271 "<meta name=\"GENERATOR\" content=\"tex2rtf\">\n"
3272 "<!-- Sitemap 1.0 -->\n"
3273 "</HEAD><BODY>\n"
3274 "<OBJECT type=\"text/site properties\">\n"
3275 " <param name=\"ImageType\" value=\"Folder\">\n"
3276 "</OBJECT>\n"
3277 "<UL>\n"
3278 "<LI> <OBJECT type=\"text/sitemap\">\n"
3279 "<param name=\"Local\" value=\"%s\">\n"
3280 "<param name=\"Name\" value=\"Contents\">\n</OBJECT>\n",
3281 FileNameFromPath(TitlepageName)
3282 );
3283
3284 }
3285
3286
3287 void HTMLWorkshopEndContents()
3288 {
3289 for (int i = HTMLWorkshopLastLevel; i >= 0; i--)
3290 fprintf(HTMLWorkshopContents, "</UL>\n");
3291 fclose(HTMLWorkshopContents);
3292 }