[INHERIT('SCREENHANDLERS','UTILITYOPS','ARGOPS',
'TREEANDLISTOPS','FLAGOPS','CONVERSION'), environment('dsrops')]

MODULE DSROPS;


CONST

  indexofpagecommand = 38;

VAR

   totallines             : [EXTERNAL] integer;
   totalgooddsrcommands : [EXTERNAL] integer;
   totalbaddsrcommands  : [EXTERNAL] integer;





[GLOBAL] FUNCTION listispagecommand( list : arglist ) : boolean;
var
  s : pckstr;
begin
  listispagecommand := false;
  if arglistlength(list) = 1 then
  begin
     s := argliteral(firstarg(list), TRUE );
     if s = 'PAGE' then
       listispagecommand := true
  end
end;



[GLOBAL] PROCEDURE checkfordsrcommand( var infile, outfile : text;
                                var dsrcommand : boolean );
var
 gotten : boolean;
begin
 if flagclass(currentchar) = control then
 begin
   getnextchar(infile, gotten);
   if gotten then
   begin
     if (flagclass(currentchar) <> comment) and (currentchar <> blank) then
         dsrcommand := true
   end
   else
   begin
     dsrcommand := false;
     texwrite(outfile, currentchar)
   end
 end
 else
   dsrcommand := false
end;




[GLOBAL] PROCEDURE parsedsrcommand( var infile, outfile : text; var list :
                                     arglist; var anothercommand : boolean;
                                     var carrychar : boolean; var charcarried : char);
const
  dontwritethem = false;
type
  charidentity = (letter, separator, number, semicolon, quote, commentchar,newdsrcommand);
var
  quotedchar : char;
  argread : argument;
  currentargclass : charidentity;
  done, gotten, atseparator, endofdsrcommand : boolean;
  i : integer;

  function charclass( ch : char ) : charidentity;
  label
     localexit;
  begin
     charclass := separator;
     if flagclass( ch ) = control then
     begin
        charclass := newdsrcommand;
        goto localexit
     end;
     if ch in ['a'..'z','A'..'Z'] then
     begin
        charclass := letter;
        goto localexit
     end;
     if ch in ['+','-','0'..'9'] then
     begin
        charclass := number;
        goto localexit
     end;
     if ch in [chr(34), chr(39)] then
     begin
        charclass := quote;
        goto localexit
     end;
     if flagclass(currentchar) = comment then
     begin
        charclass := commentchar;
        goto localexit
     end;
     if ch = ';' then
       charclass := semicolon;
     localexit : nullstatement
  end;

  procedure startarg( ch : char; var arg : argument; startset : setofargtype);
  begin
     initarg(arg, startset, ch, indexofunknowntexcommand, false);
  end;

begin
   list := nulllist;
   atseparator := false;
   endofdsrcommand := false;
   anothercommand := false;
   carrychar := false;
   repeat
        currentargclass := charclass(currentchar);
        case currentargclass of
           letter  : begin
                       atseparator := false;
                       startarg(currentchar, argread, [dsrverb,stylespecifier, textpckstr,character]);
                       done := false;
                       repeat
                           getnextchar(infile, gotten);
                           if gotten then
                           begin
                               if charclass(currentchar) = letter then
                                   appendchartoarg(currentchar, argread)
                               else
                                   done := true
                           end
                           else
                           begin
                               done := true;
                               endofdsrcommand :=  true
                           end
                       until done;
                       appendargonlist(list, argread )
                    end;
           number  : begin
                       atseparator := false;
                       startarg(currentchar, argread, [int,signedint,textpckstr,nulltype]);
                       done := false;
                       repeat
                           getnextchar(infile, gotten);
                           if gotten then
                           begin
                               if charclass(currentchar) = number then
                                   appendchartoarg(currentchar, argread)
                               else
                                   done := true
                           end
                           else
                           begin
                               done := true;
                               endofdsrcommand :=  true
                           end
                       until done;
                       appendargonlist(list, argread )
                    end;
        separator : begin
                       passblanks(infile, outfile, dontwritethem);
                       if (atseparator) and (currentchar <> lastinputchar) then
                       begin
                           startarg(blank, argread, [nulltype]);
                           appendargonlist(list, argread);
                           atseparator := false
                       end
                       else
                       begin
                           if flagclass(currentchar) = control then
                             endofdsrcommand := true
                           else
                             if charclass(currentchar) = separator then
                             begin
                               getnextchar(infile, gotten);
                               if gotten then
                                  atseparator := true
                               else
                               begin
                                  atseparator := false;
                                  startarg(blank, argread, [nulltype]);
                                  appendargonlist(list, argread);
                                  endofdsrcommand := true
                               end
                             end
                       end
                    end;
       semicolon : begin
                      endofdsrcommand := true;
                      getnextchar(infile, gotten);
                      if charclass(currentchar) = newdsrcommand then
                         currentargclass := newdsrcommand
                      else
                      begin
                        carrychar := true;
                        charcarried := currentchar
                      end
                    end;
           quote  : begin
                       quotedchar := currentchar;
                       getnextchar(infile, gotten);
                       if gotten then
                       begin
                          startarg(currentchar, argread, [quotedpckstr]);
                          done := false;
                          repeat
                             getnextchar(infile, gotten);
                             if gotten then
                             begin
                               if charclass(currentchar) = quote then
                               begin
                                   getnextchar(infile, gotten);
                                   done := true;
                                   if not gotten then
                                       endofdsrcommand := true
                               end
                               else
                                   appendchartoarg(currentchar, argread)
                             end
                             else
                             begin
                               endofdsrcommand := true;
                               done := true
                             end
                          until done
                       end
                       else
                         startarg(quotedchar, argread,[textpckstr,character]);
                       appendargonlist(list, argread)
                    end;
     commentchar : begin
                      endofdsrcommand := true
                    end;
  newdsrcommand : begin
                      endofdsrcommand := true;
                    end
     end; {case}
   until endofdsrcommand;
   if currentargclass <> newdsrcommand then
     newline( infile, outfile, false)
   else
     anothercommand := true
end;



PROCEDURE parsefile( var infile, outfile : text; textree : argtree );
const
  nocrlf = false;
  putcrlf = true;
var
  dsrcommandfound      : boolean;
  chargotten            : boolean;
  dsrarguments          : arglist;
  texcommandindex      : integer;
  nextcommandtowrite  : integer;
  successfulparse       : boolean;
  depthofsearch        : integer;
  anothercommand        : boolean;
  carrychar             : boolean;
  charcarried, copychar : char;
begin
 ttywritestring('Translating input ...');
 totalgooddsrcommands := 0;
 totalbaddsrcommands := 0;
 nextcommandtowrite := indexofunknowntexcommand;
 anothercommand := false;
 repeat
   putsecondarytexcommand( outfile, nextcommandtowrite);
   repeat
     checkfordsrcommand( infile, outfile, dsrcommandfound );
     if dsrcommandfound then
     begin
       parsedsrcommand( infile, outfile, dsrarguments, anothercommand,carrychar,charcarried);
       if listispagecommand( dsrarguments) then
       begin
         successfulparse := true;
         texcommandindex := indexofpagecommand
       end
       else
         searchtreeforlist( textree, dsrarguments,successfulparse, texcommandindex,
         depthofsearch);
       if successfulparse then
       begin
         totalgooddsrcommands := totalgooddsrcommands + 1;
         puttexcommand(outfile, texcommandindex, dsrarguments, nextcommandtowrite);
         if carrychar then
         begin
            copychar := currentchar;
            currentchar := charcarried;
            writecurrentchar( infile, outfile );
            currentchar := copychar
         end
       end
       else
       begin
         totalbaddsrcommands := totalbaddsrcommands + 1;
         write(outfile,'%Unidentified RUNOFF command "');
         dumpthelist(outfile, dsrarguments);
         writeln(outfile,'"')
       end
     end
     else
       anothercommand := false
   until (not dsrcommandfound) and (not anothercommand);
   repeat
     writecurrentchar( infile, outfile );
     getnextchar(infile, chargotten)
   until not chargotten;
   newline(infile, outfile, putcrlf)
 until eof(infile)
end;



END.