[INHERIT('UTILITYOPS','ARGOPS'), environment('flagops')]

MODULE FLAGOPS;          

CONST

  tab = 9;
  ncharsintab = 8;

TYPE
                     
dsrflagtype = record
	            representation : char;
	            turnedon : boolean
 	        end;
                     
                                 
dsrflagclasses = (notaflag, control, uppercase, lowercase, quote,
space, underline, bold, overstrike, hyphenate, break, period, capitalize,
endfootnote, comment, substitute);

flagtabletype = array[dsrflagclasses] of dsrflagtype;

tabrecordtype = record
	            tabread : boolean;
	            charcountintab : integer
	          end;

styletype = (undetermined, decimal, octal, hexidecimal, romanupper, romanlower,
	    romanmixed, letterupper, letterlower, lettermixed, nostyle);

enhancmentstates = (notenhanced, singlecharenhanced, enhancmentlocked);
    


VAR                                 

	lastinputchar, currentchar   : [EXTERNAL] char;
        capitalizetext, lowercasetext : [EXTERNAL] boolean;
	inputcontainstexcommands     : [EXTERNAL] boolean;
        inliteral                      : [EXTERNAL] boolean;
        totallines, totalchars        : [EXTERNAL] integer; 
        flagtable                      : [EXTERNAL] flagtabletype;
        tabrecord                      : [EXTERNAL] tabrecordtype;
	LOG                             : [EXTERNAL] text;    
        columncounter                  : [EXTERNAL] integer;
	infootnote                     : [EXTERNAL] boolean; 
	boldactive                     : [EXTERNAL] enhancmentstates;
        underlineactive                : [EXTERNAL] enhancmentstates;
        startnofillagain             : [EXTERNAL] boolean;   
        fill                            : [EXTERNAL] boolean;
        listnestlevel                 : [EXTERNAL] integer;

      

[GLOBAL] PROCEDURE beginnofill( var outfile : text  );
begin              
  if (fill) and (listnestlevel = 0) then
  begin
     writeln(outfile,'{\obeylines \obeyspaces % -  begin no fill');
     fill := false
  end
  else
  begin
    writeln(outfile,'% - RNOTOTEX obeylines, obeyspaces already active');
    writeln(    log,'% - RNOTOTEX obeylines, obeyspaces already active')
  end
end;




[GLOBAL] PROCEDURE endnofill( var outfile : text );
begin
   if (not fill) and (listnestlevel = 0) then
   begin
      writeln(outfile,'} % - end of no fill');    
      fill := true
   end
   else                                      
   begin
      writeln(outfile,'% - RNOTOTEX obeylines, obeyspaces not active');
      writeln(    log,'% - RNOTOTEX obeylines, obeyspaces not active')
   end
end;





        
[GLOBAL] PROCEDURE writeflagname( var outfile : text; f : dsrflagclasses );
begin          
  case f of
    notaflag   : write(outfile,'?????');
    control      : write(outfile,'CONTROL');
    uppercase    : write(outfile,'UPPERCASE');
    lowercase    : write(outfile,'LOWERCASE');
    quote        : write(outfile,'QUOTE');
    space        : write(outfile,'SPACE');
    underline    : write(outfile,'UNDERLINE');
    bold         : write(outfile,'BOLD');
    overstrike   : write(outfile,'OVERSTRIKE');
    hyphenate    : write(outfile,'HYPYENATE');
    capitalize   : write(outfile,'CAPITALIZE');
    endfootnote : write(outfile,'END FOOTNOTE');
    comment      : write(outfile,'COMMENT');
    substitute   : write(outfile,'SUBSTITUTE')
  end
end;



                   

 
[GLOBAL] FUNCTION isastylespecifier( arg : argument ) : styletype;
label
   routineexit;
var 
  s : pckstr;
  classification : styletype; 
begin        
   s := argliteral( arg, TRUE );
   classification := undetermined;
   if (s.body[1] = 'D') and (s.length = 1) then
   begin
     classification := decimal;
     goto routineexit
   end;
   if (s.body[1] = 'O') and (s.length = 1) then
   begin
     classification := octal;            
     goto routineexit
   end;
   if (s.body[1] = 'H') and (s.length = 1) then
   begin
     classification := hexidecimal;
     goto routineexit
   end;
   if (s.body = 'RU') and (s.length = 2) then
   begin
     classification := romanupper;
     goto routineexit
   end;
   if (s.body = 'RL') and (s.length = 2) then
   begin
     classification := romanlower;
     goto routineexit
   end;
   if (s.body = 'RM') and (s.length = 2) then
   begin
     classification := romanmixed;                           
     goto routineexit
   end;
   if (s.body = 'LU') and (s.length = 2) then
   begin
     classification := letterupper;
     goto routineexit
   end;
   if (s.body = 'LL') and (s.length = 2) then
   begin
     classification := letterlower;
     goto routineexit
   end;
   if (s.body = 'LM') and (s.length = 2) then
   begin
     classification := lettermixed;
     goto routineexit
   end;                         
   routineexit : isastylespecifier := classification
end;
                                


[GLOBAL] PROCEDURE initflagtable;
var
  f : dsrflagclasses;
begin
  for f := notaflag to substitute do
  case f of
       	notaflag : begin
	              flagtable[f].representation := blank;
	              flagtable[f].turnedon := false
	             end;
 	control    : begin
	              flagtable[f].representation := '.';   
	              flagtable[f].turnedon := true
	             end;
 	uppercase  : begin
	              flagtable[f].representation := '^';
	              flagtable[f].turnedon := true
	             end;
 	lowercase  : begin
	              flagtable[f].representation := '\';   
	              flagtable[f].turnedon := true
	             end;
 	quote      : begin
	              flagtable[f].representation := '_';  
	              flagtable[f].turnedon := true
	             end;
 	space      : begin
	              flagtable[f].representation := '#';  
	              flagtable[f].turnedon := true 
	             end;
 	underline  : begin
	              flagtable[f].representation := '&';  
	              flagtable[f].turnedon := true 
	             end;
 	bold       : begin
	              flagtable[f].representation := '*';  
	              flagtable[f].turnedon := false
	             end;
 	overstrike : begin
	              flagtable[f].representation := '%';  
	              flagtable[f].turnedon := false
	             end;
       	hyphenate  : begin
	              flagtable[f].representation := '=';  
	              flagtable[f].turnedon := false
	             end;
       	break      : begin
	              flagtable[f].representation := '|';  
	              flagtable[f].turnedon := false
	             end;
       	period     : begin
	              flagtable[f].representation := '+';  
	              flagtable[f].turnedon := false
	             end;
       	capitalize : begin
	              flagtable[f].representation := '<';  
	              flagtable[f].turnedon := false
	             end;
      endfootnote : begin
                       flagtable[f].representation := '!';
	               flagtable[f].turnedon := false
	             end;
       	comment    : begin
	              flagtable[f].representation := '!';  
	              flagtable[f].turnedon := true
	             end;
       	substitute : begin
	              flagtable[f].representation := '$';  
	              flagtable[f].turnedon := false
	             end
  end { case }
end; {initflagtable}   




[GLOBAL] FUNCTION flagclass( ch : char )  : dsrflagclasses;
var
   class : dsrflagclasses;
   foundclass : boolean;
begin     
   class := control;
   foundclass := false;
   while (class <> substitute) and ( not foundclass) do
     if (ch = flagtable[class].representation) and (flagtable[class].turnedon)then
        foundclass := true
     else                   
        class := succ(class);
   if foundclass then       
     if inliteral then
	if class = control then
	  flagclass := control
	else
	  flagclass := notaflag
      else
        flagclass := class
   else
     flagclass := notaflag
end;




[GLOBAL] PROCEDURE initcharreader(var f : text );
begin
   reset(f);
   lastinputchar := blank;
   read(f, currentchar);
   totallines := 0;
   totalchars := 0;       
   columncounter := 1;
   if ord(currentchar) = tab then
   begin
     tabrecord.tabread := true;
     tabrecord.charcountintab := ncharsintab
   end
   else
   begin
     tabrecord.tabread := false;
     tabrecord.charcountintab := 0
   end
end;




[GLOBAL] PROCEDURE getnextchar( var f : text; var gotten : boolean );

  function nexttabcolumn( startingcolumn : integer ) : integer;
  var
    i : integer;
  begin
    i := startingcolumn;
    repeat               
       i := i + 1
    until (i-1) mod ncharsintab = 0;
    nexttabcolumn := i;
    writeln(log,'nexttabcolumn input = ',startingcolumn:1,', output = ',i:1)
  end;
  
begin
   gotten := false;
   if NOT eof(f) then
   if NOT eoln(f) then
     with tabrecord do
     begin
        lastinputchar := currentchar;
        gotten := true;
        columncounter := columncounter + 1;
        if (tabread) and (charcountintab > 0) then
        begin
	   currentchar := blank;
	   charcountintab := charcountintab - 1;
	   if charcountintab = 0 then tabread := false
	end                            
	else
	begin
          totalchars := totalchars + 1;
          read( f, currentchar );
          if currentchar < blank then
          begin
             if ord(currentchar) = tab then
             begin
               tabread := true;
               charcountintab := nexttabcolumn( columncounter ) - columncounter-1;
               writeln(log,'charcountintab = ',charcountintab)
             end;
	     currentchar := blank
         end 
        end
     end
end;                    



[GLOBAL] PROCEDURE startunderline( var outfile : text; class : enhancmentstates);
begin 
  if class <> notenhanced then
    case underlineactive of
      notenhanced         : begin
	                       write(outfile,'\underline{');
	                       underlineactive := class
	                    end;
      singlecharenhanced : nullstatement;
      enhancmentlocked   : nullstatement
    end;
  underlineactive := class
end;                                             




[GLOBAL] PROCEDURE stopunderline( var outfile : text );
begin
  case underlineactive of
    notenhanced             : nullstatement;
    singlecharenhanced     : begin
	                         write(outfile,'} ');
	                         underlineactive := notenhanced
	                       end;
    enhancmentlocked        : nullstatement
  end
end;




[GLOBAL] PROCEDURE startbold( var outfile : text; class : enhancmentstates);
begin                 
  if class <> notenhanced then
    case boldactive of
      notenhanced         : begin
	                       write(outfile,'{\bf ');
	                       boldactive := class
	                    end;
      singlecharenhanced : nullstatement;
      enhancmentlocked    : nullstatement
    end;
  boldactive := class
end;                                             
                             



[GLOBAL] PROCEDURE stopbold( var outfile : text );
begin
   case boldactive of
     notenhanced           : nullstatement;
     singlecharenhanced   : begin
	                         write(outfile,'} ');
	                         boldactive := notenhanced
	                      end;
     enhancmentlocked      : nullstatement
   end
end;
                                                  



                            
[GLOBAL] PROCEDURE passblanks( var infile, outfile : text; writethem : boolean );
var 
   gotten, keeppassing : boolean;
begin                  
   keeppassing := true;    
   gotten := true;
   repeat
      if (currentchar = blank) and (gotten) then
      begin
         if writethem then write(outfile, blank );
         getnextchar(infile, gotten)
      end
      else
         keeppassing := false
   until NOT keeppassing                                  
end;
          
                            

[GLOBAL] PROCEDURE texwrite( var f : text; ch : char );
const         
  maxtrys = 2;
var
  ntrys : integer;
  written : boolean;
begin          
   ntrys := 0;     
   written := false;
   repeat
     if (inputcontainstexcommands) or (inliteral) then
       write(f, ch, error := continue)
     else
       if ch >= blank then
        if ch in ['#','$','%','&','_','^','{','}','~'] then
           write(f, '\',ch, error := continue)
        else
           if ch = '\' then
              write(f,'\backslash ', error := continue)
           else
              write(f, ch, error := continue);
     if status(f) > 0 then
     begin
       writeln(f, error := continue); 
       ntrys := ntrys + 1
     end
     else
       written := true     
   until (written) or (ntrys > maxtrys);
   if ntrys > maxtrys then
       errorexit('TEXWRITE','error writing to output')
end;



[GLOBAL] PROCEDURE writecurrentchar( var infile, outfile : text );
var
   gotten : boolean;
begin                                
    if capitalizetext then
       currentchar := capchar( currentchar );
    if lowercasetext then
       currentchar := lcchar( currentchar );
    case flagclass(currentchar) of              
        notaflag   : begin                   
	                  stopunderline( outfile );
	                  stopbold( outfile );
	                  texwrite(outfile, currentchar)
                       end;
	control      : begin                              
	                  stopunderline( outfile );           
	                  stopbold( outfile );                      
	                  texwrite(outfile, currentchar)
                       end;
 	uppercase    : begin
                       getnextchar(infile, gotten);
                       if gotten then
                       case flagclass(currentchar) of        
		         underline  : startunderline( outfile, enhancmentlocked);
	                 bold       : startbold( outfile, enhancmentlocked );
                         otherwise    texwrite(outfile, capchar(currentchar))
                       end
	               end;
 	lowercase    : begin                                   
                       getnextchar(infile, gotten);
                       if gotten then
	               case flagclass(currentchar) of
		         underline  : begin
	                                if underlineactive <> notenhanced then 
	                                   write(outfile,'} ');
	                                underlineactive := notenhanced
	                              end;
	                 bold       : begin
                                        if boldactive <> notenhanced then
 	                                   write(outfile,'} ');
	                                boldactive := notenhanced
	                              end;
                         otherwise    texwrite(outfile, lcchar(currentchar))
                         end
	               end;                   
 	quote        : begin
	               getnextchar(infile, gotten);
                       if gotten then      
	                texwrite(outfile, currentchar )
	              end;
 	space        : write(outfile,'\ ');
 	underline    : begin                              
                       getnextchar(infile, gotten );
                       if gotten then
                       begin
                         startunderline( outfile, singlecharenhanced);
	                 texwrite(outfile, currentchar)
                       end
	               else
	                 texwrite(outfile, currentchar)
                      end;
 	bold         : begin
	                getnextchar(infile, gotten);
                        if gotten then
                        begin
                           startbold( outfile, singlecharenhanced);
	                   texwrite(outfile, currentchar)
	                end
	                else
	                  texwrite(outfile, currentchar)
	               end;
 	overstrike   : begin
	                 getnextchar(infile, gotten);
                         if gotten then
                         begin
	                   startbold( outfile, singlecharenhanced);
	                   texwrite(outfile, currentchar)
	                 end
	                 else
	                   texwrite(outfile, currentchar)
	               end;
       	hyphenate    : write(outfile,'--');
       	break        : writeln(outfile,'\linebreak');
       	period       : write(outfile,'\nonfrenchspacing ');
       	capitalize   : begin
	                 getnextchar( infile, gotten);
	                 if gotten then
	                    texwrite(outfile, capchar(currentchar))
	               end;  
        endfootnote : begin
	                if (columncounter = 1) and (infootnote) then
	                begin
                            if not fill then
	                       endnofill( outfile );
	  	            writeln(outfile,'} % - end of footnote');
	                    writeln(    log,'} % - end of footnote');
                            infootnote := false;
	                    if startnofillagain then
	                    begin
	                       startnofillagain := false;
	                       beginnofill( outfile )
	                    end
	                end                                         
	                else
	                    texwrite(outfile, currentchar)
	               end;
       	comment    : begin
                       if flagclass(lastinputchar) = control then
	                      write(outfile,'% ')
                        else
	                   texwrite(outfile,currentchar)
	             end;
       	substitute : texwrite(outfile, currentchar)
  end { case }
end;
                                             

                        

[GLOBAL] PROCEDURE newline( var infile, outfile : text; putcrlf : boolean );
var                                                               
  gotten : boolean;
begin                   
   if eoln(infile) then 
   begin
     readln(infile);
     totallines := totallines + 1;
     columncounter := 1
   end;
   if putcrlf then 
     writeln(outfile);
   while (eoln(infile)) and (not eof(infile)) do
   begin  
     readln(infile);
     writeln(outfile);  
     columncounter := 1;                            
     totallines := totallines + 1
   end;                                      
   if not eof(infile) then
   begin 
     read(infile, currentchar);       
     totalchars := totalchars + 1;
     lastinputchar := blank
   end;                        
   if ord(currentchar) = tab then
   begin                                             
      tabrecord.charcountintab := ncharsintab;
      tabrecord.tabread := true
   end
   else
   begin
     tabrecord.charcountintab := 0;
     tabrecord.tabread := false
   end;
   if currentchar < blank then currentchar := blank
end;






[GLOBAL] PROCEDURE changeflagchar( flag : dsrflagclasses; newchar:char);
begin
   flagtable[flag].representation := newchar;
   write(log,'[internal flag representation change for ');
   writeflagname(log, flag);
   writeln(log,' to "',newchar,'"]')
end;

    

[GLOBAL] PROCEDURE turnflagon( flag : dsrflagclasses );
begin
   flagtable[flag].turnedon := true;
   write(log,'[internal flag ');
   writeflagname(log, flag);
   writeln(log,' enabled]')
end;
                                    


[GLOBAL] PROCEDURE turnflagoff( flag : dsrflagclasses );
begin
  flagtable[flag].turnedon := false;
  write(log,'[internal flag ');
  writeflagname(log, flag);
  writeln(log,' disabled]')
end;




[GLOBAL] PROCEDURE texwritearg( var outfile : text; arg : argument );
var
  s : pckstr;
  i, l : integer;
begin
  s := argliteral( arg, false );
  l := length( s );
  for i := 1 to l do  texwrite(outfile, s.body[i]);
  write(outfile, blank)
end;


END.                                                                
