

{ Turbo program patcher version 1.00A by Bela Lubkin 1/10/85
  Send suggestions via Borland SIG on CompuServe - GO BOR }
 
Program TurboPatch;
  Const
    MaxPatLen=20;
    MaxPat=10;
    MaxVer=10;
    Missing: String[30]='Missing section in TPATCH.DAT';
 
  Type
    String80=String[80];
    PatArray=Array [1..MaxPatLen] Of Byte;
 
  Var
    CommandLine: String[127] Absolute CSEG:$0080;
    PatchFile: Text;
    S: String[40];
    ComFile: File Of Byte;
    ComName: String[20];
    ComStartAddress: Integer;
    ComVersion: Integer;
    NPatches: Integer;
    PatchName: Array [1..MaxPat] Of String[80];
    NVersions: Integer;
    Version: Array [1..MaxVer] Of Record
                                    StartAddress: Integer;
                                    Name: String[30];
                                  End;
    Patch: Array [1..MaxPat,1..MaxVer] Of Record
                                            Address: Integer;
                                            Len: Byte;
                                            Pat: PatArray;
                                            UnPat: PatArray;
                                          End;
    PatchArea: PatArray;
    Applied: (Yes,No,Maybe,Cant);
    PA,PR,PP,I,J,K: Integer;
    Ans: Char;
    B,C: Byte;
 
  Procedure Error(M: String80);
 
    Procedure X;
      Var I: Integer;
 
      Begin
        I:=IOResult;
      End;
 
    Begin
      Write(M);
      {$I-} Close(PatchFile); X;
      Close(ComFile); X;
      Halt;
    End;
 
  Begin
    ComName:=Copy(CommandLine,2,127);
    WriteLn('Turbo program patcher version 1.00A by Bela Lubkin');
    Assign(PatchFile,'tpatch.dat');
    {$I-} Reset(PatchFile); {$I+}
    If IOResult<>0 Then Error('File TPATCH.DAT not found');
    ReadLn(PatchFile,S);
    If S<>'PATCH NAMES' Then Error(Missing);
    ReadLn(PatchFile,NPatches);
    If (NPatches>MaxPat) Or (NPatches<1) Then
     Begin
      Write('Number of patches not in [1..',MaxPat,']');
      Error('');
     End;
    For I:=1 To NPatches Do ReadLn(PatchFile,PatchName[I]);
    ReadLn(PatchFile,S);
    If S<>'VERSIONS' Then Error(Missing);
    ReadLn(PatchFile,NVersions);
    If (NVersions>MaxVer) Or (NVersions<1) Then
     Begin
      Write('Number of versions not in [1..',MaxVer,']');
      Error('');
     End;
    For I:=1 To NVersions Do
      With Version[I] Do
        ReadLn(PatchFile,StartAddress,Name);
    ReadLn(PatchFile,S);
    If S<>'PATCHES' Then Error(Missing);
    For I:=1 To NPatches Do
      For J:=1 To NVersions Do
        With Patch[I,J] Do
         Begin
          Read(PatchFile,Address);
          If Address<>0 Then
           Begin
            Read(PatchFile,Len);
            If (Len<1) Or (Len>MaxPatLen) Then Error('Patch too short or long in TPATCH.DAT');
            For K:=1 To Len Do Read(PatchFile,Pat[K]);
            For K:=1 To Len Do Read(PatchFile,UnPat[K]);
           End;
          ReadLn(PatchFile);
         End;
    If ComName='' Then
     Begin
      Write('Enter .COM file name: ');
      ReadLn(ComName);
     End;
    For I:=1 To Length(ComName) Do ComName[I]:=UpCase(ComName[I]);
    If Pos('.',ComName)=0 Then ComName:=ComName+'.COM';
    Assign(ComFile,ComName);
    {$I-} Reset(ComFile); {$I+}
    If IOResult<>0 Then Error(ComName+' could not be opened');
    Read(ComFile,B);
    If B<>$E9 Then Error(ComName+' is not a Turbo .COM file');
    Read(ComFile,B);
    Read(ComFile,C);
    ComStartAddress:=B+C Shl 8+$103;
    ComVersion:=0;
    For I:=1 To NVersions Do
      If ComStartAddress=Version[I].StartAddress Then ComVersion:=I;
    If ComVersion=0 Then
     Begin
      WriteLn(ComName,' is not a Turbo .COM file, or was generated by a version of Turbo');
      Error('Pascal not supported by this TPATCH.DAT')
     End
    Else WriteLn(ComName,' was created by Turbo Pascal ',Version[ComVersion].Name);
    PP:=0;
    PA:=0;
    PR:=0;
    For I:=1 To NPatches Do
      With Patch[I,ComVersion] Do
        If Address<>0 Then
         Begin
          PP:=PP+1;
          Seek(ComFile,Address-$100);
          For J:=1 To Len Do Read(ComFile,PatchArea[J]);
          Applied:=Maybe;
          For J:=1 To Len Do
            Case Applied Of
              Maybe: If PatchArea[J]=Pat[J] Then Applied:=Yes
                     Else If PatchArea[J]=UnPat[J] Then Applied:=No
                     Else Applied:=Cant;
              Yes: If PatchArea[J]<>Pat[J] Then Applied:=Cant;
              No: If PatchArea[J]<>UnPat[J] Then Applied:=Cant;
             End;
          Case Applied Of
            Cant: WriteLn('"',PatchName[I],'" cannot be applied.');
            Yes: Write('Remove');
            No: Write('Apply');
           End;
          If Applied<>Cant Then
           Begin
            Write(' "',PatchName[I],'"? ');
            ReadLn(Ans);
            If UpCase(Ans)='Y' Then
              Case Applied Of
                Yes: Begin
                       PR:=PR+1;
                       Seek(ComFile,Address-$100);
                       For J:=1 To Len Do Write(ComFile,UnPat[J]);
                     End;
                No: Begin
                      PA:=PA+1;
                      Seek(ComFile,Address-$100);
                      For J:=1 To Len Do Write(ComFile,Pat[J]);
                    End;
               End;
           End;
         End;
    If PP=0 Then Error('No applicable patches');
    WriteLn(PA,' patches applied');
    WriteLn(PR,' patches removed');
    Error(''); { Close files }
  End.
                                                                                                               