home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 1995 December / SOFM_Dec1995.bin / pc / os2 / vpascal / examples / vppatch / vppatch.pas < prev   
Pascal/Delphi Source File  |  1995-10-31  |  9KB  |  350 lines

  1. {█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█}
  2. {█                                                       █}
  3. {█      Virtual Pascal Examples  Version 1.0             █}
  4. {█      VPPATCH command line utility.                    █}
  5. {█      ─────────────────────────────────────────────────█}
  6. {█      Copyright (C) 1995 B&M&T Corporation             █}
  7. {█      ─────────────────────────────────────────────────█}
  8. {█      Written by Vitaly Miryanov                       █}
  9. {█                                                       █}
  10. {▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀}
  11.  
  12. { This command line utility is used to produce            }
  13. { Turbo Vision patch for Virtual Pascal.                  }
  14.  
  15. {$I-,V-}
  16.  
  17. program VpPatch;
  18.  
  19. uses Dos, Use32;
  20.  
  21. var
  22.   FilesOpened,StartQuote: Boolean;
  23.   PatchLineIndex,PatchLineNo,SrcLineNo,DestLineNo: Integer;
  24.   SrcLoNo,SrcHiNo: Integer;
  25.   DestLoNo,DestHiNo: Integer;
  26.   PatchFile, SrcFile, DestFile: Text;
  27.   PatchLine,TextWord: String;
  28.   DestFileName: PathStr;
  29.   PatchFileBuf,SrcFileBuf,DestFileBuf: array[1..4*1096] of Byte;
  30.  
  31. { Displays command line prompt and terminates }
  32.  
  33. procedure DisplayPrompt;
  34. begin
  35.   WriteLn('Syntax: VPPATCH PatchFile SrcDir DestDir');
  36.   WriteLn('PatchFile  = Patch file name');
  37.   WriteLn('SrcDir     = Directory with original sources');
  38.   WriteLn('DestDir    = Destination directory to hold patched sources');
  39.   Halt(1);
  40. end;
  41.  
  42. { Displays error message and terminates }
  43.  
  44. procedure Error(const ErrStr: String);
  45. begin
  46.   WriteLn('**Error**  ', ErrStr);
  47.   Halt(2);
  48. end;
  49.  
  50. { Displays error message with offended patch file line number }
  51.  
  52. procedure ErrorLineNo(const ErrStr: String);
  53. begin
  54.   WriteLn('**Error** ', ParamStr(1), '(', PatchLineNo, ') ', ErrStr);
  55. end;
  56.  
  57. { Reports bad patch file error and terminates }
  58.  
  59. procedure BadPatchFile;
  60. begin
  61.   ErrorLineNo('Syntax error');
  62.   Halt(2);
  63. end;
  64.  
  65. { Expands tabs to spaces and returns converted string }
  66.  
  67. procedure ExpandTabs(var S: String);
  68. var
  69.   I,J,K,N: Integer;
  70.   C: Char;
  71.   Dest: String;
  72. begin
  73.   J := 1;
  74.   for I := 1 to Length(S) do
  75.   begin
  76.     C := S[I];
  77.     if C <> #9 then N := 1
  78.    else
  79.     begin
  80.       N := 8 - ((J+7) and $7);
  81.       C := ' ';
  82.     end;
  83.     for K := 1 to N do
  84.     if J <= 255 then
  85.     begin
  86.       Dest[J] := C;
  87.       Inc(J);
  88.     end;
  89.   end;
  90.   Dest[0] := Chr(J-1);
  91.   S := Dest;
  92. end;
  93.  
  94. { Converts string to upper case }
  95.  
  96. function UpStr(const S: String): String;
  97. var
  98.   I: Integer;
  99.   S1: String;
  100. begin
  101.   for I := 1 to Length(S) do S1[I] := UpCase(S[I]);
  102.   S1[0] := S[0];
  103.   UpStr := S1;
  104. end;
  105.  
  106. { Reads source file line and checks for errors }
  107.  
  108. procedure ReadSrcLine(var S: String);
  109. begin
  110.   ReadLn(SrcFile, S);
  111.   Inc(SrcLineNo);
  112.   if IOResult <> 0 then Error('Error reading source file');
  113. end;
  114.  
  115. { Writes line to the destination file and checks for errors }
  116.  
  117. procedure WriteDestLine(var S: String);
  118. begin
  119.   WriteLn(DestFile, S);
  120.   Inc(DestLineNo);
  121.   if IOResult <> 0 then Error('Error writing to destination file');
  122. end;
  123.  
  124. { Reads unused source lines }
  125.  
  126. procedure PurgeSrcLines;
  127. var
  128.   S: String;
  129. begin
  130.   while SrcLineNo < SrcHiNo do ReadSrcLine(S);
  131. end;
  132.  
  133. { Closes source and destination files }
  134.  
  135. procedure CloseFiles;
  136. var
  137.   S: String;
  138. begin
  139.   if FilesOpened then
  140.   begin
  141.     PurgeSrcLines;
  142.     while not EOF(SrcFile) do
  143.     begin
  144.       ReadSrcLine(S);
  145.       WriteDestLine(S);
  146.     end;
  147.     Close(SrcFile); InOutRes := 0;
  148.     Close(DestFile); InOutRes := 0;
  149.     FilesOpened := False;
  150.   end;
  151. end;
  152.  
  153. { Gets word from patch file line }
  154.  
  155. procedure GetWord;
  156. begin
  157.   TextWord := '';
  158.   { Skip blanks }
  159.   while (PatchLineIndex <= Length(PatchLine)) and
  160.     (PatchLine[PatchLineIndex] in [#9,' ']) do Inc(PatchLineIndex);
  161.   { Extract word }
  162.   while (PatchLineIndex <= Length(PatchLine)) and
  163.     not (PatchLine[PatchLineIndex] in [#9,' ']) do
  164.   begin
  165.     Inc(TextWord[0]);
  166.     TextWord[Length(TextWord)] := PatchLine[PatchLineIndex];
  167.     Inc(PatchLineIndex);
  168.   end;
  169. end;
  170.  
  171. { Gets integer number from patch file line }
  172.  
  173. function GetNumber: Integer;
  174. var
  175.   Number,Code: Integer;
  176. begin
  177.   TextWord := '';
  178.   Number := 0;
  179.   { Extract number }
  180.   while (PatchLineIndex <= Length(PatchLine)) and
  181.     (PatchLine[PatchLineIndex] in ['0'..'9']) do
  182.   begin
  183.     Inc(TextWord[0]);
  184.     TextWord[Length(TextWord)] := PatchLine[PatchLineIndex];
  185.     Inc(PatchLineIndex);
  186.   end;
  187.   Val(TextWord, Number, Code);
  188.   if Code <> 0 then BadPatchFile;
  189.   GetNumber := Number;
  190. end;
  191.  
  192. { Returns true if next character is comma }
  193.  
  194. function CheckComma: Boolean;
  195. begin
  196.   CheckComma := False;
  197.   if (PatchLineIndex <= Length(PatchLine)) and
  198.     (PatchLine[PatchLineIndex] = ',') then
  199.   begin
  200.     CheckComma := True;
  201.     Inc(PatchLineIndex);
  202.   end;
  203. end;
  204.  
  205. { Get command letter }
  206.  
  207. function GetCommand: Char;
  208. begin
  209.   GetCommand := #0;
  210.   if (PatchLineIndex <= Length(PatchLine)) then
  211.   begin
  212.     GetCommand := PatchLine[PatchLineIndex];
  213.     Inc(PatchLineIndex);
  214.   end;
  215. end;
  216.  
  217. { Processes patch file line }
  218.  
  219. procedure ProcessPatchLine;
  220. var
  221.   Dir: DirStr;
  222.   Name: NameStr;
  223.   Ext: ExtStr;
  224.   FileName: PathStr;
  225.   S,S1: String;
  226. begin
  227.   case PatchLine[1] of
  228.     'C':
  229.     { New files are selected, open source file and create destination one }
  230.     { Example: 'Comparing BP7\APP.PAS and VP\APP.PAS'                     }
  231.     begin
  232.       GetWord;
  233.       if TextWord <> 'Comparing' then BadPatchFile;
  234.       CloseFiles;
  235.       GetWord;                            { Source file name }
  236.       FSplit(TextWord, Dir, Name, Ext);
  237.       FileName := ParamStr(2);            { Source directory }
  238.       if FileName[Length(FileName)] <> '\' then FileName := FileName + '\';
  239.       FileName := FileName + Name + Ext;
  240.       Assign(SrcFile, FileName);
  241.       SetTextBuf(SrcFile, SrcFileBuf);
  242.       Reset(SrcFile);
  243.       if IOResult <> 0 then Error('Could not open source file ' + FileName);
  244.       WriteLn('Processing ', UpStr(FileName));
  245.       FileName := ParamStr(3);            { Destination directory }
  246.       if FileName[Length(FileName)] <> '\' then FileName := FileName + '\';
  247.       FileName := FileName + Name + Ext;
  248.       Assign(DestFile, FileName);
  249.       SetTextBuf(DestFile, DestFileBuf);
  250.       Rewrite(DestFile);
  251.       if IOResult <> 0 then Error('Could not create destination file ' + FileName);
  252.       FilesOpened := True;
  253.       SrcLineNo := 0; SrcLoNo := 0; SrcHiNo := 0;
  254.       DestLineNo := 0; DestLoNo := 0; DestHiNo := 0;
  255.     end;
  256.  
  257.     '0'..'9':
  258.       { Command in one of the three valid forms:       }
  259.       { 1)   n1 a n3,n4                                }
  260.       { 2)   n1,n2 d n3                                }
  261.       { 3)   n1,n2 c n3,n4                             }
  262.       { Identical pairs where n1 = n2 or n3 = n4 are   }
  263.       { abbreviated as a single number.                }
  264.       { Examples: '13c13'                              }
  265.       {           '16a17,18'                           }
  266.       {           '18d19'                              }
  267.       begin
  268.         PurgeSrcLines;
  269.         SrcLoNo := GetNumber; SrcHiNo := SrcLoNo;
  270.         if CheckComma then SrcHiNo := GetNumber;
  271.         if not (GetCommand in ['a','d','c']) then BadPatchFile;
  272.         DestLoNo := GetNumber; DestHiNo := DestLoNo;
  273.         if CheckComma then DestHiNo := GetNumber;
  274.         StartQuote := True;
  275.       end;
  276.  
  277.     '<':
  278.       { Source file is quoted }
  279.       begin
  280.         S := Copy(PatchLine, 3, 255);
  281.         if StartQuote then
  282.           while SrcLineNo < SrcLoNo-1 do
  283.           begin
  284.             ReadSrcLine(S1);
  285.             WriteDestLine(S1);
  286.           end;
  287.         ReadSrcLine(S1);
  288.         Inc(SrcLoNo);
  289.         ExpandTabs(S1);
  290.         if UpStr(S) <> UpStr(S1) then
  291.         begin
  292.           ErrorLineNo('Invalid source file');
  293.           WriteLn('File ', TextRec(SrcFile).Name, '(', SrcLineNo, '):');
  294.           WriteLn('Expected: ''',S , '''');
  295.           WriteLn('Got:      ''',S1, '''');
  296.           Halt(2);
  297.         end;
  298.         StartQuote := False;
  299.       end;
  300.  
  301.     '>':
  302.       { Destination file is quoted }
  303.       begin
  304.         S := Copy(PatchLine, 3, 255);
  305.         if StartQuote then
  306.           while SrcLineNo < SrcLoNo do
  307.           begin
  308.             ReadSrcLine(S1);
  309.             WriteDestLine(S1);
  310.           end;
  311.         if DestLoNo-1 <> DestLineNo then BadPatchFile;
  312.         WriteDestLine(S);
  313.         Inc(DestLoNo);
  314.         StartQuote := False;
  315.       end;
  316.  
  317.     else BadPatchFile;
  318.   end;
  319. end;
  320.  
  321. { Main patch routine }
  322.  
  323. procedure DoPatch;
  324. begin
  325.   FilesOpened := False;
  326.   PatchLineNo := 0;
  327.   Assign(PatchFile, ParamStr(1));
  328.   SetTextBuf(PatchFile, PatchFileBuf);
  329.   Reset(PatchFile);
  330.   if IOResult <> 0 then Error('Could not open patch file ' + ParamStr(1));
  331.   while not EOF(PatchFile) do
  332.   begin
  333.     ReadLn(PatchFile, PatchLine);
  334.     if IOResult <> 0 then Error('Error reading patch file');
  335.     PatchLineIndex := 1;
  336.     Inc(PatchLineNo);
  337.     if PatchLine <> '' then ProcessPatchLine;
  338.   end;
  339.   Close(PatchFile); InOutRes := 0;
  340.   CloseFiles;
  341. end;
  342.  
  343. begin
  344.   WriteLn('Virtual Pascal Patch  Version 1.0 Copyright (C) 1995 B&M&T Corporation');
  345.   if ParamCount <> 3 then DisplayPrompt;
  346.   if FExpand(ParamStr(2)) = FExpand(ParamStr(3)) then
  347.     Error('Source and destination paths are the same');
  348.   DoPatch;
  349. end.
  350.