home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / utility / rtfgen.zip / RTFGEN.PAS < prev    next >
Pascal/Delphi Source File  |  1992-02-23  |  18KB  |  803 lines

  1.                   { RTFGEN }
  2.  
  3. (*********  Source code (C) Copyright 1992, by L. David Baldwin   *********)
  4. (*********                All Rights Reserved                     *********)
  5.  
  6. {$A+,B-,E-,F-,G-,I+,N-,O-,R-,S-,V-,X-}
  7. {$M 16384,0,0}
  8.  
  9. PROGRAM RTFGEN;
  10. Uses Crt{, MySubs};
  11. Const
  12.   TwipsPerSpace = 120;
  13.   DefaultFont : String[6] = '2';
  14.   DefaultFontSize : String[10] = '20';
  15.   ParaChar : Char = '`';
  16.   Tokenleng = 28;         {Max symbol length}
  17.   Tab = #9;
  18.   MaxRes = 13;
  19. Type
  20.   Symb = (
  21.     OtherChar, Comma, Colon, SemiColon, Lbrack, Rbrack, Dot, Slash,
  22.     LLbrack, RRbrack, OtherPunct, Ident, EolSy, Space, ParaSy, TabSy,
  23.     BuildTagSy, TopicSy, TitleSy, KeyWordSy, BrowseSy,
  24.     TopicStart, TopicEnd, DocStartSy, DocEndSy, CommandSy, BMCSy, BMLSy,
  25.     BMRSy, FontCommand, Number, BlockStartSy, BlockEndSy);
  26.   SymString = string[14];
  27. Var
  28.   Sy, SaveSy : Symb;
  29. Const
  30.   ResWord : array[1..MaxRes] of SymString = (
  31.     '\buildtag', '\topic', '\title', '\keyword', '\browse', '\bmc', '\bml',
  32.     '\bmr', '\docstart', '\docend', '\tab', '\blockstart', '\blockend');
  33.   ResSy : array[1..MaxRes] of Symb = (
  34.     BuildTagSy, TopicSy, TitleSy, KeyWordSy, BrowseSy, BMCSy, BMLSy,
  35.     BMRSy, DocStartSy, DocEndSy, TabSy, BlockStartSy, BlockEndSy);
  36. Type
  37.   TokenString = string[Tokenleng];
  38.   String127 = string[127];
  39.   Filestring = string[64];
  40.   PairType = array[0..1] of Char;
  41. Var
  42.   BrackCount, LineNo, Chi, ErrCount : Integer;
  43.   Pair : Word;
  44.   Spair : PairType absolute Pair;
  45.   LCh : Char absolute Pair;
  46.   UCh : Char;
  47.   St : String127;
  48.   ErrFlag, EofInf, InInclude, InTopic : Boolean;
  49.   SourceName : Filestring;
  50.   Inf, Outf : Text;
  51.   InBuff, OutBuff : array[1..1000] of Char;
  52.   Value : LongInt;
  53.   LCToken : TokenString;
  54.   OutString, GlobalHeader, TopicHeader : String;
  55.   BlockHeader : array[1..4] of String;
  56.   BIndex : Integer;
  57.  
  58. {-------------Error}
  59. PROCEDURE Error(II :Integer; S :String127);
  60. Var X,Y : Integer;
  61.   NewS : String127;
  62. begin
  63. GotoXY(1,WhereY);
  64. WriteLn(St);
  65. Y:=WhereY;
  66. X:=II-3; if X<1 then X:=1;
  67. GotoXY(X, Y);
  68. Write('^');
  69. Str(LineNo, NewS);
  70. NewS := NewS + ' Error';
  71. if S[0]>#0 then  NewS:=NewS + ', '+S;
  72. if X+Ord(NewS[0])>80 then X:=X-Ord(NewS[0]) else X:=X+1;
  73. GotoXY(X,Y);  WriteLn(NewS);
  74. ErrCount:=Succ(ErrCount);
  75. if ErrCount>6 then
  76.   begin
  77.   WriteLn('Excessive Number of Errors');
  78.   Halt(1);
  79.   end;
  80. ErrFlag := True;
  81. end;
  82.  
  83. {-------------Positn}
  84. function Positn(Pat, Src : String; I : Integer) : Integer;
  85. {find the position of a substring in a string starting at the Ith char}
  86. var
  87.   N : Integer;
  88. begin
  89. if I < 1 then I := 1;
  90. Delete(Src, 1, I-1);
  91. N := Pos(Pat, Src);
  92. if N = 0 then Positn := 0
  93.   else Positn := N+I-1;
  94. end;
  95.  
  96. {-------------OutFile}
  97. PROCEDURE OutFile(S : String);
  98. var
  99.   WriteIt : boolean;
  100.   Leng, I : Integer;
  101. begin
  102. {a hard to find bug is mismatched braces.  Keep count of these so
  103.  can keep track of matching.}
  104. I := 0;
  105. repeat
  106.   I := Positn('{', S, I+1);
  107.   if (I > 0) then
  108.     if not ((I > 1) and (S[I-1] = '\')) then Inc(BrackCount);
  109. until I = 0;
  110. repeat
  111.   I := Positn('}', S, I+1);
  112.   if (I > 0) then
  113.     if not ((I > 1) and (S[I-1] = '\')) then Dec(BrackCount);
  114. until I = 0;
  115.  
  116. {try to avoid hanging spaces on end of lines as editors delete them}
  117. Leng := Length(OutString)+Length(S);
  118. WriteIt := (Leng >= 75) and (OutString[Length(OutString)] <> ' ')
  119.         or (Leng >= 200);
  120. if WriteIt then
  121.   begin
  122.   WriteLn(Outf, OutString);
  123.   OutString := S;
  124.   end
  125. else OutString := OutString+S;
  126. end;
  127.  
  128. {-------------Flush}
  129. PROCEDURE Flush;
  130. begin
  131. if Length(OutString) > 0 then
  132.   begin WriteLn(OutF, OutString);  OutString := ''; end;
  133. end;
  134.  
  135. {-------------GetCh}
  136. PROCEDURE GetCh;
  137. {Return next char in Uch and Lch with Uch in upper case. Ignore comments}
  138. Var Comment : Boolean;
  139.   PROCEDURE GetchBasic; {read a character and a character pair}
  140.   begin
  141.   if Chi<=Ord(St[0]) then
  142.     begin  {NOTE: pair has the same address as lch}
  143.     Pair := MemW[DSeg : Ofs(St[Chi])];
  144.     if (LCh=Tab) and not InTopic then LCh:=' ';
  145.     UCh := UpCase(LCh);
  146.     Chi := Chi+1;
  147.     end
  148.   else
  149.     if not EOF(Inf) then
  150.       begin
  151.       ReadLn(Inf,St);
  152.       Inc(LineNo);
  153.       St:=St+^M;  {Add EOL}
  154.       Chi:=1;
  155.       GetCh;
  156.       end
  157.     else
  158.       begin
  159.       EofInf:=True;
  160.       if Comment then
  161.         begin
  162.         WriteLn('Open Comment at End of Input File');
  163.         Halt(1);
  164.         end;
  165.       end;
  166.   end;
  167.  
  168. begin  {Getch}
  169. repeat
  170.   if EofInf then
  171.     begin WriteLn('Unexpected End of Input File'); Halt(1) end;
  172.   Comment:=False;
  173.   GetchBasic;
  174.   if (SPair='(*') then
  175.     begin
  176.     Comment:=True;
  177.     repeat GetchBasic; until SPair='*)';
  178.     GetchBasic;  {pass by the '*'}
  179.     end;
  180. until not Comment;
  181. end;
  182.  
  183. {-----------IsPair}
  184. FUNCTION IsPair : Boolean;
  185. Const
  186.   Limit = 8;
  187.   PA : array[1..Limit] of PairType = (
  188.      '[[', ']]', '\[', '\]', '\\', '\`',
  189.      '\{', '\}');        {!! <- if '`' made optional, change!!}
  190. Var
  191.   I : Integer;
  192.   Was : Pairtype;
  193. begin
  194. IsPair := False;
  195. for I := 1 to Limit do
  196.   if PA[I] = Spair then
  197.     begin
  198.     Was := SPair;
  199.     Sy := OtherPunct;
  200.     IsPair := True;
  201.     GetCh;
  202.     case I of
  203.       5,7,8 : LCToken := Was;
  204.       1     : Sy := LLbrack;
  205.       2     : Sy := RRbrack;
  206.       else LCToken := LCh;
  207.       end;
  208.     GetCh;
  209.     Exit;
  210.     end;
  211. end;
  212.  
  213. {-------------GetNumber}
  214. FUNCTION GetNumber : Boolean;  {Pick up a Number}
  215. Var
  216.   Done : Boolean;
  217.   Code : Integer;
  218. begin
  219. case UCh of
  220.     '0'..'9' : LCToken := '';
  221.    else
  222.      begin
  223.      GetNumber := False;
  224.      Exit;
  225.      end;
  226.    end;
  227. GetNumber := True;
  228. Sy  := Number;
  229. Done := False;
  230. if not EofInf then
  231.   while not Done do
  232.     case UCh of
  233.       '0'..'9' :
  234.              begin
  235.              LCToken := LCToken+UCh;
  236.              GetCh;
  237.              end;
  238.       else Done := True;
  239.      end;
  240. Val(LCToken, Value, Code);
  241. end;
  242.  
  243. {-------------GetCommand}
  244. FUNCTION GetCommand : Boolean;  {Pick up a Command}
  245. Label 2;
  246. const
  247.   MaxFC = 10;
  248.   FontCommands : array[1..MaxFC] of string[6] =
  249.     ('f', 'fs', 'b', 'i', 'strike', 'ul', 'ulw', 'uld', 'uldb',
  250.      'plain');
  251. Var
  252.   Done : Boolean;
  253.   I : Integer;
  254.   AlphaOnly : TokenString;
  255. begin
  256. GetCommand := False;
  257. if UCh <> '\' then Exit;
  258.  
  259. GetCommand := True;
  260. Sy := CommandSy;
  261. LCToken := LCh;
  262. AlphaOnly := '';
  263. GetCh;
  264. Done := False;
  265. if not EofInf then
  266.   begin
  267.   while not Done do
  268.     case LCh of
  269.       'a'..'z' :
  270.       begin
  271.       if Length(LCToken)<Tokenleng then
  272.         begin
  273.         Inc(LCToken[0]);
  274.         LCToken[Length(LCToken)] := LCh;
  275.         Inc(AlphaOnly[0]);
  276.         AlphaOnly[Length(AlphaOnly)] := LCh;
  277.         end;
  278.       GetCh;
  279.       end;
  280.       else Done := True;
  281.      end;
  282.   if LCh = '-' then
  283.     begin
  284.     if Length(LCToken)<Tokenleng then
  285.       begin
  286.       Inc(LCToken[0]);
  287.       LCToken[Length(LCToken)] := LCh;
  288.       end;
  289.     GetCh;
  290.     end;
  291.   Done := False;
  292.   while not Done do
  293.     case LCh of
  294.       '0'..'9' :
  295.       begin
  296.       if Length(LCToken)<Tokenleng then
  297.         begin
  298.         Inc(LCToken[0]);
  299.         LCToken[Length(LCToken)] := LCh;
  300.         end;
  301.       GetCh;
  302.       end;
  303.       else Done := True;
  304.      end;
  305.   end;
  306.  
  307. for I := 1 to MaxRes do
  308.   if LCToken = ResWord[I] then
  309.     begin
  310.     Sy := ResSy[I];
  311.     GOTO 2;
  312.     end;
  313. if not InTopic then
  314.   for I := 1 to MaxFC do
  315.     if AlphaOnly = FontCommands[I] then
  316.       begin
  317.       Sy := FontCommand;
  318.       GoTo 2;
  319.       end;
  320. 2 :    {account for possible space after command}
  321. if Length(LCToken)<Tokenleng then
  322.   begin
  323.   Inc(LCToken[0]);
  324.   LCToken[Length(LCToken)] := ' ';
  325.   end;
  326. if UCh = ' ' then GetCh;  {use up a space}
  327. end;
  328.  
  329. {-------------GetIdent}
  330. FUNCTION GetIdent : Boolean;  {Pick up a Symbol}
  331. Var
  332.   Done : Boolean;
  333.   I : Integer;
  334. begin
  335. GetIdent := False;
  336. case UCh of
  337.     'A'..'Z', '_' : ;
  338.    else
  339.      Exit;
  340.    end;
  341. GetIdent := True;
  342. Sy := Ident;
  343. LCToken := LCh;
  344. GetCh;
  345. Done := False;
  346. if not EofInf then
  347.   while not Done do
  348.     case UCh of
  349.       'A'..'Z', '0'..'9', '_' :
  350.           begin
  351.       if Length(LCToken)<Tokenleng then
  352.         begin
  353.         Inc(LCToken[0]);
  354.         LCToken[Length(LCToken)] := LCh;
  355.         end;
  356.       GetCh;
  357.       end;
  358.       else Done := True;
  359.      end;
  360. end;
  361.  
  362. {-------------GetTopicEnd}
  363. FUNCTION GetTopicEnd : boolean;
  364. begin
  365. GetTopicEnd := False;
  366. if UCh <> '-' then Exit;
  367. if Pos('----', St) <> 1 then Exit;
  368. Chi := Length(St)+1;      {ignore remainder of St}
  369. if not EofInf then
  370.   GetCh;
  371. GetTopicEnd := True;
  372. if not InTopic then Error(Chi, '----- when not within topic');
  373. Sy := TopicEnd;
  374. end;
  375.  
  376. {-------------GetTopicStart}
  377. FUNCTION GetTopicStart : boolean;
  378. begin
  379. GetTopicStart := False;
  380. if UCh <> '=' then Exit;
  381. if Pos('====', St) <> 1 then Exit;
  382. Chi := Length(St)+1;      {ignore remainder of St}
  383. if not EofInf then
  384.   GetCh;
  385. GetTopicStart := True;
  386. if InTopic then Error(Chi, '==== when already within topic');
  387. Sy := TopicStart;
  388. end;
  389.  
  390. {-----------Punctuation}
  391. FUNCTION Punctuation : Boolean;
  392.   {-Check to see if Uch is a punctuation mark; if so, store the
  393.     punctuation type in Sy}
  394. Var
  395.   I : Integer;
  396. Const
  397.   Punct : string[10] = ^M^I' :;[].';
  398.   SyArray : array[1..8] of Symb = (
  399.     EOLSy, TabSy, Space, Colon, SemiColon, Lbrack, Rbrack, Dot);
  400. begin
  401. Punctuation := False;
  402. I := Pos(UCh, Punct);
  403. case I of
  404.   1..8 :
  405.     Sy := SyArray[I];
  406.   else if UCH = ParaChar then
  407.      Sy := ParaSy
  408.      else Exit;
  409.   end;
  410. Punctuation := True;
  411. case Sy of
  412.    EOLSy : LCToken := ' ';
  413.    ParaSy : LCToken := '';
  414.    TabSy : LCToken := '\tab ';
  415.    else LCToken := LCh;
  416.    end;
  417. GetCh;
  418. end;
  419.  
  420. {-----------Next}
  421.   PROCEDURE Next;
  422.     {-Get the next token on the command line}
  423.   begin                      {Next}
  424.   if EofInf then
  425.      begin
  426.      WriteLn('Unexpected end of input file');
  427.      Close(Outf);
  428.      Close(Inf);
  429.      Halt(1);
  430.      end;
  431.   if IsPair then
  432.   else if GetCommand then
  433.   else if GetIdent then
  434.   else if GetNumber then
  435.   else if GetTopicEnd then
  436.   else if GetTopicStart then
  437.   else if Punctuation then
  438.   else
  439.     begin
  440.     Sy := OtherChar;
  441.     LCToken := LCh;
  442.     if not EOFinf then GetCh;
  443.     end;
  444.   end;                       {Next}
  445.  
  446. {-------------SkipWhiteSpace}
  447. procedure SkipWhiteSpace;
  448. begin
  449. while (UCh = ' ') or (UCh = Tab) do
  450.   GetCh;
  451. end;
  452.  
  453. {-------------ParagraphText}
  454. PROCEDURE ParagraphText;
  455.  
  456.   procedure DoBitmap;
  457.   var
  458.     S : String[30];
  459.     Count : Integer;
  460.   const
  461.     FileChars : set of char =  ['A'..'Z', 'a'..'z', '0'..'9', '!', '#'..'''',
  462.         '@', '^'..'`', '~'];
  463.   begin
  464.   OutFile('\{');
  465.   case Sy of
  466.     BMCSy : S := 'bmc ';
  467.     BMRSy : S := 'bmr ';
  468.     BMLSy : S := 'bml ';
  469.     end;
  470.   SkipWhiteSpace;
  471.   Count := 0;
  472.   while LCH in FileChars do
  473.     begin
  474.     S := S+LCh;
  475.     GetCh;
  476.     Inc(Count);
  477.     end;
  478.   if (Count > 8) or (Count = 0) then Error(Chi, 'Filename Exp');
  479.   if LCh = '.' then
  480.     begin
  481.     S := S+LCh;
  482.     GetCh;
  483.     Count  := 0;
  484.     while LCH in FileChars do
  485.       begin
  486.       S := S+LCh;
  487.       GetCh;
  488.       Inc(Count);
  489.       end;
  490.     if (Count > 3) then Error(Chi, 'Filename Exp');
  491.     end;
  492.   Next;
  493.   OutFile(S+'\}');
  494.   end;
  495.  
  496.   procedure CrossRef;
  497.   var
  498.     SyWas : Symb;
  499.   begin
  500.   SyWas := Sy;
  501.   if Sy = LBrack then
  502.     OutFile('{\uldb ')
  503.   else OutFile('{\ul ');
  504.   SkipWhiteSpace;
  505.   Next;
  506.   case Sy of
  507.     BMCSy, BMLSy, BMRSy :
  508.       begin
  509.       DoBitmap;
  510.       while Sy = Space do Next;
  511.       end;
  512.     else
  513.       begin
  514.       While (Sy <> Colon) and (Sy <> EOLSy) do
  515.         begin
  516.         OutFile(LCToken);
  517.         Next;
  518.         end;
  519.       end;
  520.     end;
  521.   OutFile('}');
  522.   if Sy <> Colon then Error(Chi, 'Colon Exp');
  523.   Next;   {use up colon}
  524.   while Sy = Space do Next;
  525.   if (Sy <> Ident) and (Sy <> Dot) and (Sy <> Number) then
  526.     Error(Chi, 'Syntax Error in cross reference');
  527.   OutFile('{\v ');
  528.   repeat
  529.     OutFile(LCToken);
  530.     Next;
  531.   until (Sy <> Ident) and (Sy <> Dot) and (Sy <> Number);
  532.   OutFile('}');
  533.   while Sy = Space do Next;
  534.   if SyWas = LBrack then
  535.     begin
  536.     if Sy <> RBrack then Error(Chi, '] Exp');
  537.     end
  538.   else if Sy <> RRbrack then Error(Chi, ']] Exp');
  539.   end;
  540.  
  541. begin
  542. while (Sy <> ParaSy) and (Sy <> TopicEnd) and (Sy <> BlockStartSy)
  543.         and (Sy <> BlockEndSy) do
  544.   begin
  545.   case Sy of
  546.      EOLSy :
  547.         begin
  548.         OutFile(' ');
  549.         SkipWhiteSpace;
  550.         end;
  551.      LBrack, LLbrack : CrossRef;
  552.      BMCSy, BMLSy, BMRSy : DoBitmap;
  553.      else OutFile(LCToken);
  554.     end;
  555.   Next;
  556.   end;
  557. if Sy = ParaSy then
  558.   begin
  559.   repeat
  560.     Next;   {skip trailing stuff, mainly spaces}
  561.   until Sy = EOLSy;
  562.   Next;
  563.   end;
  564. end;
  565.  
  566. {-------------Paragraph}
  567. procedure Paragraph;
  568. var
  569.   Count : Integer;
  570.   S : String[10];
  571. begin
  572. repeat   {repeat ignores blank lines with spaces}
  573.   while Sy = EOLSy do
  574.     begin
  575.     OutFile('\par');
  576.     Next;
  577.     end;
  578.   Count := 0;
  579.   while (Sy = Space) or (Sy = TabSy) do
  580.     begin
  581.     if Sy = TabSy then
  582.       Count := ((Count div 5) +1) * 5 + 1
  583.     else Inc(Count);
  584.     Next;
  585.     end;
  586. until Sy <> EOLSy;
  587. if (Sy <> TopicEnd) and (Sy <> BlockStartSy) and (Sy <> BlockEndSy) then
  588.   begin
  589.   if Count > 0 then
  590.     begin
  591.     Str(Count * TwipsPerSpace:-1, S);
  592.     OutFile('\li'+S);
  593.     end;
  594.   {at start of each paragraph, output the paragraph commands entered in
  595.    the headers}
  596.   if BIndex > 0 then
  597.     OutFile('{'+BlockHeader[BIndex])
  598.   else
  599.     OutFile('{'+GlobalHeader+TopicHeader);
  600.   ParagraphText;   {do all the text}
  601.   OutFile('}\par\pard');
  602.   Flush;
  603.   end;
  604. end;
  605.  
  606. {-------------DoTopic}
  607. procedure DoTopic;
  608. begin
  609. OutFile('#{\footnote \pard\plain \sl240 \fs20 # ');
  610. SkipWhiteSpace;
  611. Next;
  612. while (Sy = Ident) or (Sy = Dot) or (Sy = Number) do
  613.   begin
  614.   OutFile(LCToken);
  615.   Next;
  616.   end;
  617. if Sy <> ParaSy then Error(Chi, 'Paragraph mark Exp')
  618. else Next;
  619. OutFile('}');
  620. Flush;
  621. end;
  622.  
  623. {-------------DoBrowse}
  624. procedure DoBrowse;
  625. var
  626.   Err : boolean;
  627. begin
  628. OutFile('+{\footnote \pard\plain \sl240 \fs20 + ');
  629. SkipWhiteSpace;
  630. Next;
  631. repeat    {Browse symbol can contain many things up to ':' }
  632.   case Sy of
  633.       OtherChar, Comma, SemiColon, Lbrack, Rbrack, Dot, Slash,
  634.       OtherPunct, Ident, Space, TabSy, Number : Err := False;
  635.     else Err := True;
  636.     end;
  637.   if Err then Error(Chi, 'Syntax error in \Browse');
  638.   OutFile(LCToken);
  639.   Next;
  640. until (Sy = Colon) or (Sy = ParaSy) or (Sy = EOLsy);
  641. if Sy = Colon then
  642.   begin
  643.   SkipWhiteSpace;
  644.   Next;
  645.   if Sy <> Number then Error(Chi, 'Number Exp in Browse');
  646.   OutFile(':'+LCToken);
  647.   SkipWhiteSpace;
  648.   Next;
  649.   end
  650. else Error(Chi, 'Colon Exp');
  651. if Sy <> ParaSy then Error(Chi, 'Paragraph mark Exp');
  652. OutFile('}');
  653. Flush;
  654. Next;
  655. end;
  656.  
  657. {-------------DoKeyWord}
  658. procedure DoKeyWord;
  659. var
  660.   Err : boolean;
  661.   Ch : Char;
  662.   S : String[10];
  663. begin
  664. Case Sy of
  665.   KeyWordSy : Ch := 'K';
  666.   TitleSy : Ch := '$';
  667.   BuildTagSy : Ch := '*';
  668.   end;
  669. S := LCToken;   {save for possible error msg}
  670. OutFile(Ch+'{\footnote \pard\plain \sl240 \fs20 '+Ch+' ');
  671. SkipWhiteSpace;
  672. Next;
  673. repeat    {symbols can contain many things }
  674.   case Sy of
  675.       OtherChar, Comma, Colon, SemiColon, Lbrack, Rbrack, Dot, Slash,
  676.       OtherPunct, Ident, Space, TabSy, Number : Err := False;
  677.     else Err := True;
  678.     end;
  679.   if Err then Error(Chi, 'Syntax error in '+S);
  680.   OutFile(LCToken);
  681.   Next;
  682. until (Sy = ParaSy) or (Sy = EOLSy);
  683. if Sy <> ParaSy then Error(Chi, 'Paragraph mark exp');
  684. OutFile('}');
  685. Flush;
  686. Next;
  687. end;
  688.  
  689. {-------------DoPage}
  690. PROCEDURE DoPage;
  691. begin
  692. InTopic := True;
  693. Next;
  694. while Sy <> TopicEnd do
  695.   if Sy = BlockStartSy then
  696.     begin
  697.     if BIndex >= 4 then Error(Chi, 'Too many nested blocks')
  698.       else Inc(BIndex);
  699.     BlockHeader[BIndex] := '';
  700.     Next;
  701.     while (Sy <> ParaSy) and (Sy <> EOLSy) do
  702.       begin
  703.       if Sy = CommandSy then
  704.     BlockHeader[BIndex] := BlockHeader[BIndex]+LCToken
  705.       else if Sy <> Space then Error(Chi, 'Command Expected');
  706.       Next;
  707.       end;
  708.     if Sy = ParaSy then Next;
  709.     if Sy = EOLSy then Next;
  710.     end
  711.   else if Sy = BlockEndSy then
  712.     begin
  713.     if BIndex < 1 then Error(Chi, 'Unmatched \blockend')
  714.       else Dec(BIndex);
  715.     while Sy <> EOLSy do Next;  {\BlockEnd should be on its own line}
  716.     Next;
  717.     end
  718.   else
  719.     Paragraph;
  720. if not EofInf then Next;
  721. OutFile('}\page');  Flush;
  722. if BIndex <> 0 then
  723.   begin
  724.   Error(Chi, 'Unmatched \blockstart in previous topic');
  725.   BIndex := 0;
  726.   end;
  727. InTopic := False;
  728. if BrackCount <> 0 then
  729.   begin
  730.   Error(Chi, '{..} imbalance in last topic');
  731.   BrackCount := 0;
  732.   end;
  733. end;
  734.  
  735. {-------------DoDocument}
  736. PROCEDURE DoDocument;
  737. begin
  738. Flush;
  739. Next;
  740. if Sy <> DocEndSy then OutFile('{');
  741. While Sy <> DocEndSy do
  742.   case Sy of
  743.     TopicSy : DoTopic;
  744.     KeyWordSy, BuildTagSy, TitleSy :
  745.          DoKeyWord;
  746.     BrowseSy : DoBrowse;
  747.     TopicStart :
  748.       begin
  749.       DoPage;
  750.       TopicHeader := '';   {get ready for a new topic header string}
  751.       while (Sy = EOLSy) or (Sy = space) or (Sy = TabSy) do Next;
  752.       if Sy <> DocEndSy  then Outfile('{');
  753.       end;
  754.     EolSy : Next;
  755.     CommandSy :
  756.       begin
  757.       TopicHeader := TopicHeader+LCToken;  {add in commands}
  758.       Next;
  759.       end;
  760.     FontCommand :
  761.       begin
  762.       OutFile(LCToken);
  763.       Next;
  764.       end;
  765.     else Next;    {ignore other junk}
  766.     end;
  767. Flush;
  768. OutFile('}');
  769. end;
  770.  
  771. {$I COMMAND.INC}
  772.  
  773. {-------------MAIN}
  774. begin
  775. ErrCount := 0; LineNo := 0; BIndex := 0; BrackCount := 0;
  776. OutString := '';
  777. GlobalHeader := '';
  778. TopicHeader := '';
  779. if ParamCount >= 1 then CommandInput else PromptForInput;
  780. ReadHeader;
  781. EofInf := False;  InTopic := False;  ErrFlag := False;
  782. InInclude := False;
  783. OutFile('\f'+DefaultFont+'\fs'+DefaultFontSize);
  784. St[0] := #0;  Chi := 1;  {get the reading started}
  785. GetCh;
  786. Next;
  787. while not EofInf and (Sy <> DocStartSy) do
  788.   begin
  789.   if Sy = CommandSy then
  790.     GlobalHeader := GlobalHeader+LCToken
  791.   else if Sy = FontCommand then
  792.     OutFile(LCToken);    {else ignore}
  793.   Next;
  794.   end;
  795. if Sy = DocStartSy then DoDocument;
  796. Flush;
  797.  
  798. Close(Inf);
  799. Close(Outf);
  800. if ErrFlag then Halt(1);
  801. end.
  802.  
  803.