program freqcomp (engfreq, substtable, infile, input, output);

{*******************************************************************************
  Letter Frequency counter Version 2.5:
                          
    This program counts the occurence frequency of each letter (ignoring case)
    in a piece of text saved in the file "infile".
    The results are then compared to a  standard english frequency    
    distribution table saved as a file "engfreq".
                   
    The program then formulates a _possible_ substitution table  
    for use with a letter substitution decoder/encoder. The      
    substitution table is stored in the file "substtable" which contains 
    the table sorted by letter frequency 

    This algorithm was developed by Stuart Prescott to assist in the 
    cryptanalysis of classical ciphers.

    Written by Stuart Prescott      20/03/96                  
    Last modified                   07/04/96                  
 
    Copyright (c) MCMXCVI, Stuart Prescott                  
*******************************************************************************}

{*******************************************************************************
    Required includes:						   
	lowercase.i       	(returns lowercase value of char)  
   
  	isletter.i	    	(returns TRUE if char is a letter) 

	index.i			(returns position of letter in alphabet)
	
	unindex.i		(returns 'c'th letter of the alphabet)


	SelectionSort.i		(uses the Selction Sort Algorithm)

	ReadStdFreqs.i	    	(reads the std English freqs from file engfreq)

*******************************************************************************}
const
    MAXLETTER = 26;

    DEBUGSort        = FALSE;
    DEBUGAssessFreqs = FALSE;
    DEBUGCountFreqs  = FALSE;
    DEBUGOutputFreqs = FALSE;

type
    FreqRecordType  = record
			 letter : char;
			 count  : integer;
		      end;

    MonoArrayType   = array [ 1 .. MAXLETTER ]
		      of FreqRecordType;

var
    totalletters	              	{count of all letters}
		: integer;	
    
    letters,	 
    english          		   	{array of normal frequencies 
    					  read in from file engfreq}
    		: MonoArrayType;

    infile,				{File containing codetext}
    engfreq,	                        {Input file for std freqs}
    substtable	                        {Output files for substtable}
		: text;	

{******************************************************************************}

#include 'lowercase.i'
#include 'isletter.i'
#include 'index.i'
#include 'unindex.i'

#include 'SelectionSort.i' 
#include 'ReadStdFreqs.i'

{******************************************************************************}
procedure InitArrays
    (
    var code	    : MonoArrayType
    );
    
    var
	c				{dummy counter}
		: integer;    

    { P: TRUE}
    begin
	for c := 1 to MAXLETTER do begin
	    code[c].letter := unindex(c);
	    code[c].count  := 0
	end;
    end;    {procedure InitArrays}
    { R: each .count is zero and each [c].letter is the 'c'th letter}
{******************************************************************************}
procedure CountFreqs 
    (
    var code	    : MonoArrayType; 
    var total	    : integer
    );

    var 
	ch
		: char;
		
    { P: code initialised as .count=0}
    begin
	total := 0;                         {initialize counter}
	reset(infile);
	
	{read through file (using standard input file commands}
	writeln ('Reading in code from file infile. . .');
	while not eof(infile) do begin                   {start file ops}
	    if eoln(infile) then begin
		readln(infile);        {get rid of the EOLN}
		{writeln;}
	    end
	    else begin
		read(infile, ch);
		{write (ch);}
		if isletter(ch) then begin
		    code[index(ch)].count := code[index(ch)].count +1;
		    total := total +1;
		end;
	    end; {if eoln}
	end; {while}
    end;        {proc CountFreqs}
    { R: each letter of the infile has been counted}

{******************************************************************************}
procedure OutputFreqs
    (
    var code,
	stds	    : MonoArrayType;
    total	    : integer
    );
    
    var
	c
		: integer;
	
	percentfreq
		:real;
		
    { P: code contains the frequency counts for the text.}
    begin
	write ('Sorting standard frequencies table... ');
	SelectionSort (stds);    	{sort out frequencies so that displayed}
	write ('Sorting this messages'' frequency table... ');
	SelectionSort (code);    	{ in descending freq so that comparable}

	{write out substtable}
	writeln ('Saving substitution table in file: "substtable"');
	rewrite(substtable);
	writeln;
	writeln ('-----CODETEXT--------   --POSSIBLE PLAINTEXT--');
	writeln ('                              EQUIVALENTS');
	writeln ('letter   freq    freq%       freq%     letter');
	writeln ('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
	for c := 1 to 26 do begin
	    percentfreq := code[c].count / total * 100;
	    write ((code[c].letter) :4);
	    write ((code[c].count)  :9   , (percentfreq)    :9:2);
	    write ((stds[c].count/100) :12:2, (stds[c].letter) :9  );
	    writeln;

	    write (substtable, (code[c].letter) :1);
	    write (substtable, (stds[c].letter)    :3);
	    writeln (substtable);
	end;
	writeln;
	writeln ('Substitution table saved in file: "substtable"');
	writeln;
    end;         {proc: OutputFreqs}
    { R: a tabular representation of the results is displayed and outputed}
    
{******************************************************************************}
{******************************************************************************}
begin   {main program}

    InitArrays(letters);    
    ReadStdFreqs(english);                {english is variable}
    CountFreqs(letters, totalletters);    {both arguments variables}
    OutputFreqs(letters, english, totalletters); {letters & english variable}

end.    {main program}
{******************************************************************************}
{******************************************************************************}


