Oberon/ETH Oberon/2.3.7/HTML.Mod

(* ETH Oberon, Copyright 1990-2003 Computer Systems Institute, ETH Zurich, CH-8092 Zurich. Refer to the license.txt file provided with this distribution. *) MODULE HTML;	(** portable *) (* jm 26.8.94 *) IMPORT &#9;Files, Objects, Texts, Oberon, Out; CONST (* possible values of the variable typ denoting the paragraph type *) &#9;para &#61; 0;			(* Normal paragraph in xxx12.Scn.Fnt or xxx12i.Scn.Fnt *) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;(* Paragraphs are delimited by one or more empty lines *) &#9;title &#61; 1;			 (* Title when first character is red *) &#9;heading &#61; 2;	 (* Heading when in xxx12b.Scn.Fnt *) &#9;bullet &#61; 3;		 (* Bullet when "*" is first character on a line *) &#9;line &#61; 4;			 (* Horizontal ruler when "-" is first character on a line *) &#9;pre &#61; 5;			 (* pre-formatted when in xxx10.Scn.Fnt *) &#9;tab &#61; 09X; &#9; &#9;DocHeader &#61; TRUE;	(* include document header comment *) &#9;BodyColor &#61; TRUE;	(* set body color - HTML 4-specific *) VAR &#9;out&#58; Files.Rider; &#9;italic&#58; BOOLEAN; &#9;sep&#58; CHAR; PROCEDURE S(s&#58; ARRAY OF CHAR); VAR i&#58; INTEGER; BEGIN &#9;i &#58;&#61; 0; &#9;WHILE s&#91;i&#93; # 0X DO Files.Write(out, s&#91;i&#93;); INC(i) END END S; PROCEDURE C(ch&#58; CHAR); BEGIN Files.Write(out, ch) END C; PROCEDURE L; BEGIN Files.Write(out, sep); END L; (* Check if font matches type. type &#61; digit &#123; digit &#125; ("." &#124; "b" &#124; "i"). *) PROCEDURE MatchFont(font&#58; ARRAY OF CHAR; type&#58; ARRAY OF CHAR)&#58; BOOLEAN; VAR i, j&#58; LONGINT; BEGIN &#9;i &#58;&#61; 0; &#9;WHILE (font&#91;i&#93; # 0X) &#38; ((font&#91;i&#93; &#60; "0") OR (font&#91;i&#93; &#62; "9")) DO	(* skip name *) &#9;&#9;INC(i) &#9;END; &#9;j &#58;&#61; 0; &#9;WHILE (font&#91;i&#93; # 0X) &#38; (font&#91;i&#93; &#62;&#61; "0") &#38; (font&#91;i&#93; &#60;&#61; "9") &#38; (font&#91;i&#93; &#61; type&#91;j&#93;) DO &#9;&#9;INC(i); INC(j) &#9;END; &#9;RETURN (font&#91;i&#93; &#61; type&#91;j&#93;) END MatchFont; (* Delimit a paragraph&#58; begins at lastnl and ends at end *) PROCEDURE GetPara(T&#58; Texts.Text; VAR R&#58; Texts.Reader; VAR beg, end&#58; LONGINT; VAR typ&#58; SHORTINT); VAR ch, firstch&#58; CHAR; firstfnt&#58; Objects.Library; firstcol&#58; INTEGER; lastnl&#58; LONGINT; BEGIN &#9;beg &#58;&#61; Texts.Pos(R); end &#58;&#61; beg; lastnl &#58;&#61; beg; &#9; &#9;(* skip empty lines *) &#9;Texts.Read(R, ch); &#9;WHILE &#126;R.eot &#38; (ch &#60;&#61; " ") DO &#9;&#9;INC(beg); &#9;&#9;IF ch &#61; 0DX THEN lastnl &#58;&#61; beg END; &#9;&#9;Texts.Read(R, ch) &#9;END; &#9; &#9;IF &#126;R.eot THEN &#9;&#9;firstch &#58;&#61; ch; firstfnt &#58;&#61; R.lib; firstcol &#58;&#61; R.col; &#9;&#9;LOOP &#9;&#9;&#9;WHILE &#126;R.eot &#38; (ch # 0DX) DO Texts.Read(R, ch) END; (* read till first nl *) &#9;&#9;&#9;IF R.eot THEN EXIT END; &#9;&#9;&#9;IF ch &#61; 0DX THEN &#9;&#9;&#9;&#9;end &#58;&#61; Texts.Pos(R)-1; &#9;&#9;&#9;&#9;Texts.Read(R, ch); &#9;&#9;&#9;&#9;WHILE &#126;R.eot &#38; (ch &#61; " ") OR (ch &#61; tab) DO Texts.Read(R, ch) END; &#9;&#9;&#9;&#9;IF ch &#61; "*" THEN Texts.OpenReader(R, T, Texts.Pos(R)-1); EXIT END; &#9;&#9;&#9;&#9;IF ch &#61; 0DX THEN EXIT END &#9;&#9;&#9;END &#9;&#9;END; &#9;&#9;IF firstcol &#61; 1 THEN (* red *) typ &#58;&#61; title &#9;&#9;ELSIF MatchFont(firstfnt.name, "12b") THEN typ &#58;&#61; heading &#9;&#9;ELSIF MatchFont(firstfnt.name, "10.") THEN typ &#58;&#61; pre; beg &#58;&#61; lastnl; &#9;&#9;ELSIF firstch &#61; "*" THEN typ &#58;&#61; bullet &#9;&#9;ELSIF firstch &#61; "-" THEN typ &#58;&#61; line &#9;&#9;ELSE typ &#58;&#61; para &#9;&#9;END &#9;END END GetPara; PROCEDURE WriteStretch(T&#58; Texts.Text; beg, end&#58; LONGINT); VAR R&#58; Texts.Reader; ch&#58; CHAR; lastlib&#58; Objects.Library; BEGIN &#9;IF end &#62; beg THEN &#9;&#9;Texts.OpenReader(R, T, beg); &#9;&#9;Texts.Read(R, ch); lastlib &#58;&#61; R.lib; &#9;&#9;WHILE beg &#60; end DO &#9;&#9;&#9;IF R.lib # lastlib THEN &#9;&#9;&#9;&#9;IF MatchFont(R.lib.name, "12i") THEN &#9;&#9;&#9;&#9;&#9;IF &#126;italic THEN S("&#60;i&#62;"); italic &#58;&#61; TRUE END &#9;&#9;&#9;&#9;ELSE &#9;&#9;&#9;&#9;&#9;IF italic THEN S("&#60;/i&#62;"); italic &#58;&#61; FALSE END &#9;&#9;&#9;&#9;END; &#9;&#9;&#9;&#9;lastlib &#58;&#61; R.lib &#9;&#9;&#9;END; &#9;&#9;&#9;IF ch &#61; "&uuml;" THEN S("&#38;uuml;") &#9;&#9;&#9;ELSIF ch &#61; "&Uuml;" THEN S("&#38;Uuml;") &#9;&#9;&#9;ELSIF ch &#61; "&ugrave;" THEN S("&#38;ugrave;") &#9;&#9;&#9;ELSIF ch &#61; "&auml;" THEN S("&#38;auml;") &#9;&#9;&#9;ELSIF ch &#61; "&Auml;" THEN S("&#38;Auml;") &#9;&#9;&#9;ELSIF ch &#61; "&aacute;" THEN S("&#38;aacute;") &#9;&#9;&#9;ELSIF ch &#61; "&agrave;" THEN S("&#38;agrave;") &#9;&#9;&#9;ELSIF ch &#61; "&euml;" THEN S("&#38;euml;") &#9;&#9;&#9;ELSIF ch &#61; "&eacute;" THEN S("&#38;eacute;") &#9;&#9;&#9;ELSIF ch &#61; "&egrave;" THEN S("&#38;egrave;") &#9;&#9;&#9;ELSIF ch &#61; "&ouml;" THEN S("&#38;ouml;") &#9;&#9;&#9;ELSIF ch &#61; "&Ouml;" THEN S("&#38;Ouml;") &#9;&#9;&#9;ELSIF ch &#61; "&ograve;" THEN S("&#38;ograve;") &#9;&#9;&#9;ELSIF ch &#61; "&iuml;" THEN S("&#38;iuml;") &#9;&#9;&#9;ELSIF ch &#61; "&igrave;" THEN S("&#38;igrave;") &#9;&#9;&#9;ELSIF ch &#61; 0DX THEN C(" "); C(sep) &#9;&#9;&#9;ELSIF ch &#61; tab THEN S("&#38;nbsp; &#38;nbsp; &#38;nbsp;") &#9;&#9;&#9;ELSIF (ch &#62;&#61; " ") OR (ch &#61; "-") THEN &#9;&#9;&#9;&#9;C(ch) &#9;&#9;&#9;END; &#9;&#9;&#9;Texts.Read(R, ch); &#9;&#9;&#9;INC(beg) &#9;&#9;END &#9;END END WriteStretch; PROCEDURE WritePara(T&#58; Texts.Text; beg, end&#58; LONGINT); VAR R&#58; Texts.Reader; ch&#58; CHAR; col&#58; INTEGER; &#9;pos, lstart&#58; LONGINT; anchor&#58; ARRAY 512 OF CHAR; apos&#58; INTEGER; BEGIN col &#58;&#61; -1; pos &#58;&#61; beg; anchor &#58;&#61; ""; &#9;Texts.OpenReader(R, T, beg); &#9;Texts.Read(R, ch); &#9;WHILE pos &#60; end DO &#9;&#9;IF (R.col &#61; 3) &#38; (col # 3) THEN (* start link *) &#9;&#9;&#9;WriteStretch(T, beg, pos); beg &#58;&#61; pos &#9;&#9;END; &#9;&#9;col &#58;&#61; R.col; &#9;&#9;&#32; &#9;&#9;IF (col &#61; 3) &#38; (ch &#61; "&#123;") THEN (* reading an anchor *) &#9;&#9;&#9;lstart &#58;&#61; pos; &#9;&#9;&#9;INC(pos); Texts.Read(R, ch); &#9;&#9;&#9;apos &#58;&#61; 0; &#9;&#9;&#9;WHILE &#126;R.eot &#38; (apos &#60; LEN(anchor)) &#38; (ch # "&#125;") DO &#9;&#9;&#9;&#9;anchor&#91;apos&#93; &#58;&#61; ch; INC(apos); &#9;&#9;&#9;&#9;INC(pos); &#9;&#9;&#9;&#9;Texts.Read(R, ch) &#9;&#9;&#9;END; &#9;&#9;&#9;anchor&#91;apos&#93; &#58;&#61; 0X; &#9;&#9;&#9;S("&#60;a href&#61;"); C(22X); S(anchor); C(22X); C("&#62;"); &#9;&#9;&#9;WriteStretch(T, beg, lstart); beg &#58;&#61; pos+1; &#9;&#9;&#9;S("&#60;/a&#62;") &#9;&#9;ELSE INC(pos); Texts.Read(R, ch) &#9;&#9;END &#9;END; &#9;WriteStretch(T, beg, end) END WritePara; PROCEDURE GetPrefix(T&#58; Texts.Text; VAR beg, end&#58; LONGINT; VAR s&#58; ARRAY OF CHAR); VAR R&#58; Texts.Reader; old&#58; LONGINT; ch&#58; CHAR; i&#58; INTEGER; BEGIN &#9;old &#58;&#61; beg; i &#58;&#61; 0; &#9;Texts.OpenReader(R, T, beg); &#9;Texts.Read(R, ch); &#9;WHILE &#126;R.eot &#38; (ch # "&#58;") &#38; (beg &#60; end) DO &#9;&#9;IF (ch &#62; " ") &#38; (i &#60; LEN(s) - 1) THEN s&#91;i&#93; &#58;&#61; ch; INC(i) END; &#9;&#9;INC(beg); &#9;&#9;Texts.Read(R, ch) &#9;END; &#9;IF ch &#61; "&#58;" THEN s&#91;i&#93; &#58;&#61; 0X; INC(beg) &#9;ELSE s&#91;0&#93; &#58;&#61; 0X; beg &#58;&#61; old &#9;END END GetPrefix; PROCEDURE ConvertText(T&#58; Texts.Text; start&#58; LONGINT; VAR filename&#58; ARRAY OF CHAR); VAR R&#58; Texts.Reader; beg, end, nbeg, nend&#58; LONGINT; typ, ntyp&#58; SHORTINT; body&#58; BOOLEAN; &#9;PROCEDURE StartBody; &#9;BEGIN &#9;&#9;S("&#60;/head&#62;"); L; &#9;&#9;IF BodyColor THEN &#9;&#9;&#9;S("&#60;body BGCOLOR&#61;"); C(22X); S("#FFFFFF"); C(22X); S("&#62;"); L &#9;&#9;ELSE &#9;&#9;&#9;S("&#60;body&#62;"); L &#9;&#9;END; &#9;&#9;body &#58;&#61; TRUE &#9;END StartBody; &#9; BEGIN &#9;italic &#58;&#61; FALSE; body &#58;&#61; FALSE; &#9;Texts.OpenReader(R, T, start); &#9;GetPara(T, R, beg, end, typ); &#9;IF DocHeader THEN &#9;&#9;S("&#60;!DOCTYPE HTML PUBLIC "); C(22X); S("-//W3C//DTD HTML 4.01 Transitional//EN"); C(22X); S("&#62;"); L &#9;END; &#9;S("&#60;html&#62;"); L; &#9;S("&#60;head&#62;"); L; &#9;S("&#60;title&#62;"); &#9;IF typ &#61; title THEN &#9;&#9;GetPrefix(T, beg, end, filename); (* Skip that file name, discarding it *) &#9;&#9;WritePara(T, beg, end); &#9;&#9;beg &#58;&#61; end	(* title paragraph already written *) &#9;ELSE &#9;&#9;S("Untitled") &#9;END; &#9;S("&#60;/title&#62;"); L; &#9;S(&#39;&#60;meta http-equiv&#61;"Content-Type" content&#61;"text/html; charset&#61;iso-8859-1"&#62;&#39;); L; &#9;WHILE &#126;R.eot DO &#9;&#9;IF &#126;body &#38; (typ # title) THEN StartBody END; (* first non-title paragraph starts body *) &#9;&#9;GetPara(T, R, nbeg, nend, ntyp); &#9;&#9;IF body &#38; (ntyp &#61; title) THEN ntyp &#58;&#61; para END; (* treat a title paragraph in body like normal *) &#9;&#9;IF typ &#61; bullet THEN S("&#60;li&#62;"); INC(beg) &#9;&#9;ELSIF typ &#61; heading THEN S("&#60;h2&#62;") &#9;&#9;ELSE (* skip *) &#9;&#9;END; &#9;&#9;IF typ &#61; line THEN S("&#60;hr&#62;") (* Horizontal Ruler *) &#9;&#9; (* ELSIF typ &#61; title THEN *) (* skip *) &#9;&#9;ELSE &#9;&#9;&#9;WritePara(T, beg, end); (* write previous *) &#9;&#9;&#9;IF typ &#61; pre THEN C(0DX) END &#9;&#9;END; &#9;&#9;IF typ &#61; heading THEN S("&#60;/h2&#62;") END; &#9;&#9; IF beg # end THEN L END ; &#9;&#9; &#9;&#9;(* List *) &#9;&#9;IF (ntyp &#61; bullet) &#38; (typ # bullet) THEN (* open list *) &#9;&#9;&#9;S("&#60;ul&#62;"); L &#9;&#9;ELSIF (ntyp # bullet) &#38; (typ &#61; bullet) THEN (* close list *) &#9;&#9;&#9; S("&#60;/ul&#62;"); L &#9;&#9;END; &#9;&#9; &#9;&#9;(* Pre-formatted text *) &#9;&#9;IF (ntyp &#61; pre) &#38; (typ # pre) THEN (* start pre-formatted text *) &#9;&#9;&#9;IF &#126;body THEN StartBody END; &#9;&#9;&#9;S("&#60;pre&#62;") &#9;&#9;ELSIF (ntyp # pre) &#38; (typ &#61; pre) THEN &#9;&#9;&#9;S("&#60;/pre&#62;"); L &#9;&#9;END; &#9;&#9; &#9;&#9;(* Separate 2 consecutive "normal" paragraphs with a paragraph break, except two preformatteds *) &#9;&#9;IF (ntyp &#61; para) &#38; (typ &#61; para) THEN S("&#60;p&#62;"); L END; &#9;&#9; &#9;&#9;end &#58;&#61; nend; beg &#58;&#61; nbeg; typ &#58;&#61; ntyp &#9;END; &#9; IF &#126;body &#38; (typ # title) THEN StartBody END; &#9;WritePara(T, beg, end); (* write previous *) &#9;IF (typ &#61; bullet) THEN (* close list *) &#9;&#9; S("&#60;/ul&#62;"); L &#9;END; &#9;IF (typ &#61; pre) THEN &#9;&#9;S("&#60;/pre&#62;"); L &#9;END; &#9;S("&#60;/body&#62;"); L; &#9;S("&#60;/html&#62;"); L END ConvertText; (** Show a preview of the HTML text in a text viewer - Processes ONLY one text! *) PROCEDURE Show*; VAR S&#58; Texts.Scanner; T, t&#58; Texts.Text; time, beg, end&#58; LONGINT; &#9;filename&#58; ARRAY 64 OF CHAR; f&#58; Files.File; BEGIN &#9;sep &#58;&#61; 0DX; &#9;beg &#58;&#61; 0;		(* Process from the beginning of the text. Modified if "@" used *) &#9;Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); &#9;Texts.Scan(S); T &#58;&#61; NIL; &#9;IF (S.class &#61; Texts.Char) &#38; (S.c &#61; "*") THEN &#9;&#9;T &#58;&#61; Oberon.MarkedText &#9;ELSIF (S.class &#61; Texts.Char) &#38; (S.c &#61; "^") THEN &#9;&#9;Oberon.GetSelection(T, beg, end, time); &#9;&#9;IF time &#62;&#61; 0 THEN &#9;&#9;&#9;Texts.OpenScanner(S, T, beg); &#9;&#9;&#9;Texts.Scan(S); &#9;&#9;&#9;IF (S.class &#61; Texts.Name) THEN &#9;&#9;&#9;&#9;NEW(T); Texts.Open(T, S.s); &#9;&#9;&#9;&#9;IF T.len &#61; 0 THEN T &#58;&#61; NIL END &#9;&#9;&#9;END &#9;&#9;ELSE T &#58;&#61; NIL &#9;&#9;END &#9;ELSIF (S.class &#61; Texts.Char) &#38; (S.c &#61; "@") THEN &#9;&#9;Oberon.GetSelection(T, beg, end, time); &#9;&#9;IF time &#60; 0 THEN T &#58;&#61; NIL END &#9;END; &#9;IF T # NIL THEN &#9;&#9;f &#58;&#61; Files.New("Temp.HTML.tmp"); &#9;&#9;Files.Set(out, f, 0); &#9;&#9;ConvertText(T, beg, filename); &#9;&#9;Files.Register(f); &#9;&#9;NEW(t); Texts.Open(t, "Temp.HTML.tmp"); &#9;&#9;Oberon.OpenText(filename, t, 400, 200) &#9;END END Show; PROCEDURE Compile*; &#9;VAR S&#58; Texts.Scanner; T&#58; Texts.Text; filename&#58; ARRAY 64 OF CHAR; f&#58; Files.File; beg, end, time&#58; LONGINT; &#9;PROCEDURE CompileT; &#9;&#9;VAR R&#58; Texts.Reader; beg, end&#58; LONGINT; typ&#58; SHORTINT; &#9;&#9;&#9;&#9;res, i&#58; INTEGER; bak&#58; ARRAY 64 OF CHAR; &#9;BEGIN &#9;&#9;IF T.len &#62; 0 THEN &#9;&#9;(* Get the file name from the source text, at the beginning i.e. pos 0 *) &#9;&#9;&#9;Texts.OpenReader(R, T, 0); &#9;&#9;&#9;GetPara(T, R, beg, end, typ); &#9;&#9;&#9;IF typ &#61; title THEN &#9;&#9;&#9;&#9;GetPrefix(T, beg, end, filename) &#9;&#9;&#9;END; &#9;&#9;(* *) &#9;&#9;&#9;IF filename # "" THEN &#9;&#9;&#9;&#9;Out.String(filename); &#9;&#9;&#9;(* Rename the file &#39;fileName.Bak&#39; *) &#9;&#9;&#9;&#9;i &#58;&#61; 0; &#9;&#9;&#9;&#9;WHILE filename&#91;i&#93; # 0X DO bak&#91;i&#93; &#58;&#61; filename&#91;i&#93;; INC(i) END; &#9;&#9;&#9;&#9;bak&#91;i&#93; &#58;&#61; "."; bak&#91;i+1&#93; &#58;&#61; "B"; bak&#91;i+2&#93; &#58;&#61; "a"; bak&#91;i+3&#93; &#58;&#61; "k"; bak&#91;i+4&#93; &#58;&#61; 0X; &#9;&#9;&#9;&#9;Files.Rename(filename, bak, res); &#9;&#9;&#9;(* *) &#9;&#9;&#9;&#9;f &#58;&#61; Files.New(filename); &#9;&#9;&#9;&#9;Files.Set(out, f, 0); &#9;&#9;&#9;&#9;ConvertText(T, 0, filename); &#9;&#9;&#9;&#9;Files.Register(f); &#9;&#9;&#9;&#9;Out.Int(Files.Length(f), 10); &#9;&#9;&#9;ELSE Out.String("no destination file name in text") &#9;&#9;&#9;END &#9;&#9;END; &#9;&#9;Out.Ln &#9;END CompileT; &#9; BEGIN &#9;sep &#58;&#61; 0AX; &#9;Out.String("HTML.Compile"); Out.Ln; &#9;Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); &#9;Texts.Scan(S); &#9;IF (S.class &#61; Texts.Char) &#38; (S.c &#61; "*") THEN &#9;&#9;T &#58;&#61; Oberon.MarkedText; &#9;&#9;IF T # NIL THEN &#9;&#9;&#9;CompileT &#9;&#9;END &#9;ELSE &#9;&#9;end &#58;&#61; MAX(LONGINT) - 100; &#9;&#9;IF (S.class &#61; Texts.Char) &#38; (S.c &#61; "^") THEN &#9;&#9;&#9;Oberon.GetSelection(T, beg, end, time); &#9;&#9;&#9;IF time &#62;&#61; 0 THEN Texts.OpenScanner(S, T, beg); Texts.Scan(S) END &#9;&#9;END; &#9;&#9;WHILE (S.class &#61; Texts.Name) &#38; (Texts.Pos(S) &#60; end + S.len + 1) DO &#9;&#9;&#9;Out.String(S.s); Out.String(" &#61;&#62; "); &#9;&#9;&#9;NEW(T); Texts.Open(T, S.s); &#9;&#9;&#9;CompileT; &#9;&#9;&#9;Texts.Scan(S) &#9;&#9;END &#9;END END Compile; END HTML. System.Free HTML &#126; HTML.Compile ^	HTML.Compile * HTML.Show ^		HTML.Show *		HTML.Show @