unit U_MatchMerge;
{Copyright  © 2005, Gary Darby,  www.DelphiForFun.org
 This program may be used or modified for any non-commercial purpose
 so long as this original notice remains in place.
 All other rights are reserved
 }

{
MatchMerge merges two files and optionally
writes the output to a new file.

Input files are checked to ensure that they are
in sequence and may be sortedf if not.

Duplicates may be eliminated or retained in the
output.

Potential enhancements include the ability to merge
more than 2 files and to select fields from the
record for comparison.
}

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ShellAPI;

type
TForm1 = class(TForm)
    MergeBtn: TButton;
    ListBox1: TListBox;
    ListBox2: TListBox;
    ListBox3: TListBox;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Memo1: TMemo;
    OpenDialog1: TOpenDialog;
    OpenDialog2: TOpenDialog;
    Size1lbl: TLabel;
    Size2Lbl: TLabel;
    Size3Lbl: TLabel;
    SaveDialog1: TSaveDialog;
    StaticText1: TStaticText;
    DupsBox: TCheckBox;
    DupsLbl: TLabel;
procedure MergeBtnClick(Sender: TObject);
procedure StaticText1Click(Sender: TObject);
public
file1,file2:text;
    line1,line2:string;
function  GetNext(var LineOut:string):integer;
Procedure CheckFile(filename:string);
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

{************* TForm1.GetNext **********}
function  TForm1.GetNext(var LineOut:string):integer;
{return the next record in sequence from 2 files}
{Return values:0 = done, 1 = record from file1, 2 = record from file2}
var eofrec:string; {end of file flag}
begin
eofrec:=stringofchar(char(255),10);
  result:=0;   lineout:='';
if (line1=eofrec) and (line2=eofrec) then exit;
{Ansicomparetext will not compare properly against our eofrec,
   but Uppercase function will}
If uppercase(Line1)<=uppercase(Line2) then  {line1 is not high, return line1}
begin
result:=1; lineout:=Line1;
{read ahead for next time}
if not eof(file1) then readln(File1,line1)
else line1:=Eofrec;
end
else {return line2}
begin
result:=2;  lineout:=Line2;
{read ahead for next time}
If not eof(file2) then  readln(File2,line2)
else line2:=Eofrec;
end;
end;

{************** CheckFile **********}
procedure TForm1.checkfile(filename:string);
{check if files are in sequence and sort if needed and requested }
var
list:Tstringlist;
     newname:string;
     i:integer;
begin
list:=Tstringlist.create;
     list.loadfromfile(filename);
if list.count>0 then
begin
for i:=0 to list.count-2 do
if ansicomparetext(list[i],list[i+1])>0 then
begin
if messagedlg('File '+filename+' is not in sequence, sort it now?'
+#13+list[i]+' before '+list[i+1] ,
                            mtconfirmation,[mbyes,mbno],0)=mryes then
begin
newname:=changefileext(filename,'.~txt');
           list.savetofile(newname);
           list.sort;
           list.savetofile(FileName);
end;
         break;
end;
end;
     list.free;
end; {checkfile}


{************ MergeBtnClick **********}
procedure TForm1.MergeBtnClick(Sender: TObject);
{Get names of two files and merge them}
var
flag, dups3:integer;
  line, where:string;
begin
if opendialog1.execute and opendialog2.Execute then
begin
{Sort input files if necessary}
checkfile(opendialog1.filename);
    checkfile(opendialog2.filename);
{load the files into listboxes}
listbox1.items.loadfromfile(Opendialog1.filename);
    Size1Lbl.caption:=inttostr(listbox1.items.count)+' records';
    listbox2.items.loadfromfile(Opendialog2.filename);
    Size2Lbl.caption:=inttostr(listbox2.items.count)+' records';
    listbox3.clear;
{Open files and initialize Line1 and Line2 by reading the 1st record from each}
assignfile(file1,opendialog1.filename);
    assignfile(file2,opendialog2.filename);
    reset(File1);  reset(file2);
    readln(file1,line1);  readln(file2,line2);
    dups3:=0;
{loop getting records in sequence until all records have been retrieved}
while getnext(line)>0 do
with listbox3.items do
begin
If (count>0) and  (ansicomparetext(line,strings[count-1])=0) then inc(dups3);
if (not (dupsbox.checked))
or (count=0)
or ((dupsbox.checked) and (ansicomparetext(line,strings[count-1])<>0))
then add(line);
end;
    size3lbl.caption:=inttostr(listbox3.items.count)+' records';
If dupsbox.checked then dupslbl.caption:=inttostr(dups3)+' duplicates dropped.'
else dupslbl.caption:='including '+inttostr(dups3)+' duplicates.';
    closefile(File1);
    closefile(file2);
end;
if savedialog1.execute then listbox3.items.savetofile(savedialog1.filename);
end;

procedure TForm1.StaticText1Click(Sender: TObject);
begin
ShellExecute(Handle, 'open', 'http://www.delphiforfun.org/',
nil, nil, SW_SHOWNORMAL) ;
end;

end.