home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 2 / ctrom_ii_b.zip / ctrom_ii_b / PROGRAM / PASCAL / DSUTIL11 / FINDREP / FINDREP.PAS < prev   
Pascal/Delphi Source File  |  1993-10-28  |  31KB  |  913 lines

  1. {-----------------------------------------------------------------------}
  2. { PROJECT        NON-PROFIT HIGH QUALITY PROFESSIONAL SOFTWARE,  }
  3. {            AVAILABLE FOR ALL WORLD                }
  4. { LIBRARY        SYSTEM UTILITIES                                }
  5. { MODULE        FIND_AND_REPLACE                                }
  6. { FILE NAME        FINDREP.PAS                    }
  7. { PURPOSE               Replaces any occurence of wanted string         }
  8. { VERSION        1.30                        }
  9. { DATE            28-Oct-93                    }
  10. { DESIGN        Dmitry Stefankov                }
  11. { IMPLEMENTATION    Dmitry Stefankov                 }
  12. { COMPANY        Freelance Software Engineer            }
  13. { ADDRESS        Isakowskogo str, 4-2-30                }
  14. {            Moscow, 123181                    }
  15. {            USSR                        }
  16. {            Tel. 007 (095) 944-6304                }
  17. { COPYRIGHT NOTICE    Copyright (C) 1987-1993, Dmitry Stefankov    }
  18. { RESTRICTED RIGHTS    AVAILABLE ONLY FOR FREE DISTRIBUTION,           }
  19. {            NOT FOR COMMERCIAL PURPOSE            }
  20. { COMPUTER        IBM PC or compatible                }
  21. { OPERATING SYSTEM    MS/PC-DOS Version 3.30 or higher        }
  22. { COMPILER        Turbo Pascal Version 6.0            }
  23. {                       (Borland International Inc.) or compatible      }
  24. { ASSEMBLY LANGUAGE    Microsoft MASM 5.10 or compatible               }
  25. { LINKER        Turbo Pascal internal                           }
  26. { ARGUMENTS        <infile>     -  input  stream                   }
  27. {                       <outfile>    -  output stream                   }
  28. {                       <instr>      -  input string                    }
  29. {                       <outstr>     -  output string                   }
  30. {                       <query>      -  ask user for replace match      }
  31. { RETURN        None                        }
  32. { REQUIRES        None                                            }
  33. { NATURAL LANGUAGE      English Language                                 }
  34. { SPECIAL        None                        }
  35. { DESCRIPTION        1.Read input stream                             }
  36. {                       2.Find match pattern                            }
  37. {                       3.If found then replace to another string       }
  38. {                       4.Write output stream                           }
  39. { REVISION HISTORY    Dima Stefankov (DS)                }
  40. {               1.00   22-Jan-92  DS  initilal release        }
  41. {                       1.01   23-Jan-92  DS  added text format string, }
  42. {                                             added documentation       }
  43. {                       1.02   24-Jan-92  DS  some corrections          }
  44. {                       1.03   17-Mar-92  DS  fixed a bug with hexformat}
  45. {            1.10   25-Aug-92  DS  updated documentation    }
  46. {                       1.20   08-Oct-92  DS  some style corrections    }
  47. {                       1.21   27-Oct-92  DS  some corrections          }
  48. {                       1.22   04-Nov-92  DS  some updates              }
  49. {            1.23   23-Dec-92  DS  added empty string     }
  50. {                          as replace string        }
  51. {                       1.24   16-Jan-93  DS  fixed a bug with hexadec. }
  52. {                          output            }
  53. {                       1.25   07-Apr-93  DS  some corrections          }
  54. {                       1.26   24-May-93  DS  some style updates        }
  55. {                       1.27   10-Jun-93  DS  fixed a bug with upcases  }
  56. {            1.28   05-Jul-93  DS  updated documentation    }
  57. {                       1.29   09-Sep-93  DS  fixed an input stream EOF }
  58. {                                             bug at buffer processong  }
  59. {            1.30   28-Oct-93  DS  some style updates    }
  60. {-----------------------------------------------------------------------}
  61.  
  62.  
  63. {*======================= PROGRAM HEADER PART ==========================*}
  64.  
  65. PROGRAM   HexaDecimalFindAndReplaceFileUtility;
  66.  
  67.  
  68. {*** other modules ***}
  69. {*USES;*}
  70.  
  71.  
  72. {** switches for compilation **}
  73. {$S-}                  {*  stack checking  *}
  74. {$R-}                     {*  range checking  *}
  75. {$M 16384,131072,131072}  {*  memory allocation  *}
  76.  
  77.  
  78.  
  79. {*========================== CONSTANTS PART ============================*}
  80.  
  81. CONST
  82.  
  83.      asPurpose                  =       'FindRep Utility';
  84.      asVersion                  =       '1.30';
  85.      asAuthor                   =       'Dima Stefankov';
  86.      asCopyright                =       'Copyright (c) 1987, 1993';
  87.      asProgram                  =       'FindRep';
  88.      asProgramPrompt            =       asProgram+': ';
  89.      asProgramU                 =       'FINDREP';
  90.  
  91.      { exit codes }
  92.      errOK            =     0;
  93.      errTerminateOK             =     0;
  94.      errBadParmsNumber          =     1;
  95.      errSourceNotFound          =     2;
  96.      errDestDontWrite           =     3;
  97.      errSameNames               =     4;
  98.      errSrcOpenFailed           =     6;
  99.      errDestCreateFailed        =     7;
  100.      errBadInStr                =     8;
  101.      errBadOutStr               =     9;
  102.      errSrcReadFailed        =    10;
  103.      errDestWriteFailed        =    11;    
  104.  
  105.      achHexPrefix               =     '$';
  106.      achDosExtMark              =     '.';
  107.      asInDefExt                 =     'exe';
  108.      asOutDefExt                =     'exe';
  109.  
  110.      aPercent100        =     100;
  111.      aHexRadix                  =     16;
  112.      aMaxOnHeap                 =     65520;
  113.  
  114.      achNULL                    =     #0;
  115.      achHTAB                    =     #9;
  116.      achSkip                    =     '.';
  117.      achUserWant                =     'Y';
  118.      achUserDontWant            =     'N';
  119.  
  120.  
  121. {*==================== TYPE DECLARATIONS PART ==========================*}
  122.  
  123. TYPE
  124.  
  125.     STR2        =       STRING[2];
  126.     STR4        =       STRING[4];
  127.     STR8        =       STRING[8];
  128.  
  129.  
  130. {*====================== TYPED CONSTANTS PART ==========================*}
  131.  
  132. CONST
  133.  
  134.      setHexChars  :    SET OF System.Char  =  ['0'..'9','A'..'F','a'..'f'];
  135.  
  136.      galiMatchCount       :       System.Longint      =  0;
  137.      galiReplaceCount     :       System.Longint      =  0;
  138.      gabUserAskToReplace  :       System.Boolean      =  System.False;
  139.      gabFileToReplace     :       System.Boolean      =  System.True;
  140.      gabUserAskToDisplay  :       System.Boolean      =  System.False;
  141.  
  142.  
  143. {*=========================== VARIABLES PART ===========================*}
  144.  
  145. VAR
  146.  
  147.    gfInputStream        :       FILE;
  148.    gsInFileName         :       STRING[80];
  149.  
  150.    gfOutputStream       :       FILE;
  151.    gsOutFileName        :       STRING[80];
  152.  
  153.    gddInOffsetInFile    :       System.Longint;
  154.    gddInByteCount       :       System.Longint;
  155.    gddTotalFileBytes    :    System.Longint;
  156.    gpInMemoryBlock      :       System.Pointer;
  157.    gdwInMemBlockSize    :       System.Word;
  158.    gdwInBytesRead       :       System.Word;
  159.    gdwInBytesReadAdd    :       System.Word;
  160.    gdwInBytesReadTest   :       System.Word;
  161.    gdwOutBytesWritten   :       System.Word;
  162.  
  163.    gpOutMemoryBlock     :       System.Pointer;
  164.    gdwOutMemBlockSize   :       System.Word;
  165.  
  166.  
  167.    giErrorCode          :       System.Integer;
  168.  
  169.    gsTempInput          :       STRING;
  170.    gsInSearch           :       STRING;
  171.    gsOutReplace         :       STRING;
  172.    gchInUser            :       System.Char;
  173.  
  174.  
  175. {*=========================== FUNCTIONAL PART ==========================*}
  176.  
  177. FUNCTION  _fndbHexCharToBin(chIn: System.Char) : System.Byte; assembler;
  178. {* Converts hexadecimal char to binary. *}
  179. asm
  180.         mov   al,chIn        { AL = chIn }
  181.         sub   al,'0'         { AL <- AL - '0' }
  182.  
  183.         cmp   al,9           { test for digit }
  184.         jbe   @Done
  185.  
  186.         and   al,11011111b   { make uppercase }
  187.         sub   al,'A'-'9'-1   { AL = 'A'..'F' }
  188.  
  189.       @Done:
  190.                              { AL = function result }
  191. END;
  192.   {asm-end}
  193. { _fndbHexCharToBin }
  194.  
  195.  
  196. FUNCTION  _fnsUpcaseStr(sInput : STRING) : STRING;
  197. {* Make all uppercase. *}
  198. VAR
  199.   dbIndex  :  System.BYTE;
  200.   dbCount  :  System.BYTE;
  201.  
  202. BEGIN
  203.   dbCount := System.Length(sInput);
  204.  
  205.   IF (dbCount <> 0)
  206.     THEN  FOR  dbIndex :=  1  TO  dbCount  DO
  207.             sInput[dbIndex] := System.Upcase(sInput[dbIndex]);
  208.           {for-to-do}
  209.   {if-then}
  210.  
  211.    _fnsUpcaseStr := sInput;
  212. END; { _fnsUpcaseStr }
  213.  
  214.  
  215. FUNCTION  _fnbFileExist(VAR fStruc : FILE; sFileName : STRING) : System.Boolean;
  216. {* Check that file exits. *}
  217. VAR
  218.   bResult  :  System.Boolean;
  219.  
  220. BEGIN
  221.   {** attempt to open the file **}
  222.   System.Assign(fStruc,sFileName);
  223.   {$I-}
  224.   System.Reset(fStruc);
  225.   {$I+}
  226.  
  227.   {** copy the result of last I/O operation **}
  228.   bResult := (System.IOResult = 0);
  229.  
  230.   IF (bResult)
  231.     THEN  System.Close(fStruc);
  232.   {if-then}
  233.  
  234.   _fnbFileExist := bResult;
  235. END; { _fnbFileExist }
  236.  
  237.  
  238. FUNCTION   _fnsByteToHexFmt(dbInput : System.Byte) : STR2;
  239. {* Converts a byte to the hex format number representation. *}
  240. CONST
  241.     dbHexCharTable : ARRAY[0..15] OF System.Char = '0123456789ABCDEF';
  242.  
  243. BEGIN
  244.   _fnsByteToHexFmt := dbHexCharTable[dbInput SHR 4] +
  245.                       dbHexCharTable[dbInput AND $0F];
  246. END;  { _fnsByteToHexFmt }
  247.  
  248.  
  249. FUNCTION   _fnsWordToHexFmt(dwInput : System.Word) : STR4;
  250. {* Converts a word to the hex format number representation. *}
  251. BEGIN
  252.   _fnsWordToHexFmt := _fnsByteToHexFmt(System.Hi(dwInput)) +
  253.                       _fnsByteToHexFmt(System.Lo(dwInput));
  254. END;  { _fnsWordToHexFmt }
  255.  
  256.  
  257. FUNCTION   _fnsDoubleWordToHexFmt(ddInput : System.Longint) : STR8;
  258. {* Converts a double word to the hex format number representation. *}
  259. BEGIN
  260.   _fnsDoubleWordToHexFmt := _fnsWordToHexFmt(System.Word(ddInput SHR 16)) +
  261.                       _fnsWordToHexFmt(System.Word(ddInput and $0000FFFF));
  262. END;  { _fnsDoubleWordToHexFmt }
  263.  
  264.  
  265. FUNCTION  _fnsForceFileNameExt(sFileName, sDefExt : STRING) : STRING;
  266. {* Add extension for filename if not present. *}
  267. BEGIN
  268.    IF (System.Pos(achDosExtMark,sFileName) = 0)
  269.      THEN sFileName := sFileName + achDosExtMark + sDefExt;
  270.    {if-then}
  271.   _fnsForceFileNameExt := sFileName;
  272. END;
  273. { _fnsForceFileNameExt }
  274.  
  275.  
  276. FUNCTION   _fnchGetFirstChar(sInput : STRING) : System.Char;
  277. {* Returns a first char from string. *}
  278. VAR
  279.   chTemp  :  System.Char;
  280.  
  281. BEGIN
  282.    IF (System.Length(sInput) <> 0)
  283.      THEN  chTemp := sInput[1]
  284.      ELSE  chTemp := achNULL;
  285.    {if-then-else}
  286.   _fnchGetFirstChar := chTemp;
  287. END;
  288. { _fnchGetFirstChar }
  289.  
  290.  
  291. {*=========================== PROCEDURAL PART ==========================*}
  292.  
  293. PROCEDURE    _CopyrightDisplay;
  294. {* Outputs the copyright notice. *}
  295. BEGIN
  296.      System.WriteLn(asPurpose+
  297.                     '  Version '+
  298.                     asVersion+
  299.                     ', '+
  300.                     asCopyright+
  301.                     '   '+
  302.                     asAuthor);
  303. END;  { _CopyrightDisplay }
  304.  
  305.  
  306. PROCEDURE  _TranslateStr(sInput         :  STRING;
  307.                                VAR sOutput    :  STRING;
  308.                                VAR iErrorCode :  System.Integer);
  309. {* Convert the string from hex/text format to char representation. *}
  310. VAR
  311.   dbIndex    :  System.BYTE;
  312.   dbCount    :  System.BYTE;
  313.   bFormatOk  :  System.Boolean;
  314.  
  315. BEGIN
  316.   {* set initial values *}
  317.       dbCount    := 0;
  318.   IF  (System.Length(sInput) = 0)
  319.     THEN  BEGIN
  320.       sOutput[0] := System.Char(dbCount);
  321.       iErrorCode := 0;
  322.           END
  323.     ELSE  BEGIN
  324.       bFormatOk  := System.True;
  325.       iErrorCode := -1;
  326.       dbIndex    := 1;
  327.           END;
  328.  
  329.   IF  (sInput[dbIndex] = achHexPrefix) THEN
  330.     BEGIN
  331.  
  332.      IF (System.Length(sInput) >= 2) AND (sInput[dbIndex+1] = achHexPrefix)
  333.      THEN
  334.          BEGIN
  335.               {* just a copy text string but skip 1st char *}
  336.                 sOutput := sInput;
  337.                 System.Delete(sOutput,1,1);
  338.                 iErrorCode := 0;
  339.          END
  340.      ELSE
  341.       BEGIN
  342.       {* skip a ID char *}
  343.       System.Inc(dbIndex);
  344.  
  345.       {* test for valid count of chars *}
  346.       IF  NOT(System.Odd(System.Length(sInput)))
  347.          THEN  bFormatOk := System.False;
  348.       {if-then}
  349.  
  350.       WHILE (bFormatOk) AND (dbIndex <= System.Length(sInput))  DO
  351.       BEGIN
  352.         IF  (sInput[dbIndex] IN setHexChars)
  353.         THEN
  354.           BEGIN
  355.              {* byte is constructed from 2 chars *}
  356.              IF  System.ODD(dbIndex)  THEN
  357.                 BEGIN
  358.                   {* Note: counter is used also as index *}
  359.                   System.Inc(dbCount);
  360.                   sOutput[dbCount] := System.Char((_fndbHexCharToBin(sInput[dbIndex-1]) SHL 4)
  361.                                        + _fndbHexCharToBin(sInput[dbIndex]));
  362.                 END;
  363.              {if-then}
  364.  
  365.              {* try next char* }
  366.              System.Inc(dbIndex);
  367.           END
  368.         ELSE
  369.           bFormatOK := System.False;
  370.      {if-then-else}
  371.       END;
  372.       {while-do}
  373.       END;
  374.       {if-else }
  375.     END
  376.     ELSE BEGIN
  377.            {* just a copy text string *}
  378.            sOutput := sInput;
  379.            iErrorCode := 0;
  380.          END;
  381.     {if-then-else }
  382.  
  383.   IF (bFormatOK) AND (dbCount <> 0)
  384.     THEN  BEGIN
  385.       sOutput[0] := System.Char(dbCount);
  386.       iErrorCode := 0;
  387.           END;
  388.   {if-then}
  389. END; { _TranslateStr }
  390.  
  391.  
  392. PROCEDURE  _ProcessBuffer(VAR fInFile        :   FILE;
  393.                               pInMemBuf      :  System.Pointer;
  394.                               dwInByteCount  :  System.Word;
  395.                               dwInBufSize    :  System.Word;
  396.                           VAR fOutFile       :  FILE;
  397.                               pOutMemBuf     :  System.Pointer;
  398.                               dwOutBufSize   :  System.Word;
  399.                               sSearchInput   :  STRING;
  400.                               sReplaceOutput :  STRING;
  401.                           VAR dwAddBytesRW   :  System.Word);
  402. {* Writes the contents of buffer with replacing if requires. *}
  403. VAR
  404.   sSaveBytes            :  STRING;
  405.   ddMatchOffsetInFile   :  System.Longint;
  406.   dwInBufOfs            :  System.Word;
  407.   dwOutBufOfs           :  System.Word;
  408.   dbIndex               :  System.Byte;
  409.   dbCount               :  System.Byte;
  410.   chInByte              :  System.Char;
  411.   bMatch                :  System.Boolean;
  412.   bReplaceMake          :  System.Boolean;
  413.   bInFilePast           :  System.Boolean;
  414.  
  415.  
  416. PROCEDURE _PutByteToOutput(VAR dwOutBufferOffset : System.Word; dbInPut : System.Byte);
  417. {* Put a byte to buffer and write a buffer to disk if buffer is full. *}
  418. BEGIN
  419.   asm
  420.         les     di, dwOutBufferOffset   { get a pointer to offset        }
  421.         mov     ax, es:[di]             { fetch an offset               }
  422.     mov    di, [bp+4]        { Turbo calculation of pOutMemBuf   }
  423.         les     di, ss:[di+12h]         { ES:DI <- Pointer to Output Buffer }
  424.         add     di, ax                  { add an offset                    }
  425.         mov     al, dbInPut             { get a putting value               }
  426.         mov    es:[di], al        { write this byte            }
  427.   end;
  428.   {*** The following PASCAL-code is functionally identical to the ASM-code **}
  429.   {** System.Mem[System.Seg(pOutMemBuf^):System.Ofs(pOutMemBuf^)+dwOutBufferOffset] := dbInPut; **}
  430.   System.Inc(dwOutBufferOffset);
  431.  
  432.   {* check is buffer full *}
  433.   IF (dwOutBufferOffset = dwOutBufSize)
  434.     THEN  BEGIN
  435.          {$I-}
  436.              System.BlockWrite(fOutFile,
  437.                               System.Mem[System.Seg(pOutMemBuf^):System.Ofs(pOutMemBuf^)],
  438.                               dwOutBufSize,
  439.                               gdwOutBytesWritten);
  440.          {$I+}
  441.          IF (dwOutBufSize <> gdwOutBytesWritten)
  442.            THEN  BEGIN
  443.             System.WriteLn(asProgramPrompt+'Unable to write output file '+gsOutFileName);
  444.             System.Halt(errDestWriteFailed);
  445.             END;
  446.            {if-then}
  447.               dwOutBufferOffset := 0;
  448.           END;
  449.   {if-then}
  450. END; { _PutByteToOutput }
  451.  
  452.  
  453. PROCEDURE _GetByteFromInput(VAR dwInBufferOffset : System.Word;
  454.                             VAR dbOut            : System.Char;
  455.                             VAR dwInTotalCount   : System.Word;
  456.                             VAR bInPast          : System.Boolean);
  457. {* Get a byte from buffer and check for empty. *}
  458. BEGIN
  459.   {* check is buffer empty *}
  460.   IF (dwInBufferOffset = dwInBufSize)
  461.    THEN  BEGIN
  462.              {* now we read only by one byte *}
  463.              dwInBufSize := 1;
  464.          {$I-}
  465.              System.BlockRead(fInFile,
  466.                               System.Mem[System.Seg(pInMemBuf^):System.Ofs(pInMemBuf^)],
  467.                               dwInBufSize,
  468.                               gdwInBytesReadTest);
  469.          {$I+}
  470.              {* special case: EOF detected *}
  471.               IF (gdwInBytesReadTest = 0)
  472.                 THEN BEGIN
  473.                        dwInBufSize      := 0;
  474.                        bInPast          := System.True;
  475.                        dwInBufferOffset := 0;
  476.                        dwInTotalCount   := 1;
  477.                      END
  478.                 ELSE
  479.                   BEGIN
  480.                     dwInBufferOffset := 0;
  481.                     dwInTotalCount   := dwInBufSize;
  482.                     System.Inc(dwAddBytesRW);
  483.                   END;
  484.               {if-then-else }
  485.           END;
  486.   {if-then}
  487.  
  488.    asm
  489.          les    di, dwInBufferOffset    { get a pointer to offset          }
  490.          mov    ax, es:[di]             { fetch an offset                  }
  491.      mov    di, [bp+4]        { Turbo calculation of pInMemBuf   }
  492.      les    di, ss:[di+1Eh]        { ES:DI <- Pointer to Input Buffer }
  493.          add    di, ax                  { add offset in this buffer        }
  494.          mov    al, es:[di]             { get a byte from this buffer      }
  495.          les    di, dbOut               { get a pointer to byte variable   }
  496.          mov    es:[di], al             { save a byte to a pointer         }
  497.    end;
  498.   {**** The following PASCAL-code is functionally identical to the ASM-code **
  499.    dbOut := System.Char(System.Mem[System.Seg(pInMemBuf^):
  500.                                     System.Ofs(pInMemBuf^)+dwInBufferOffset]);
  501.    ****}
  502.    System.Inc(dwInBufferOffset);
  503.    System.Dec(dwInTotalCount);
  504.    System.Inc(gddInOffsetInFile);
  505. END; { _GetByteFromInput }
  506.  
  507.  
  508. BEGIN
  509.   {** initial values **}
  510.   dwInBufOfs   := 0;
  511.   dwOutBufOfs  := 0;
  512.   dwAddBytesRW := 0;
  513.   bInFilePast  := System.False;
  514.  
  515.   {** read/search&replace/write **}
  516.   WHILE  (dwInByteCount <> 0) DO
  517.   BEGIN
  518.     _GetByteFromInput(dwInBufOfs,chInByte,dwInByteCount,bInFilePast);
  519.     IF (chInByte <> sSearchInput[1])
  520.     THEN  BEGIN
  521.               IF (gabFileToReplace)
  522.                 THEN
  523.                  _PutByteToOutput(dwOutBufOfs,System.Byte(chInByte));
  524.               {if-then}
  525.           END
  526.     {* first match char found *}
  527.     ELSE BEGIN
  528.             {* initials *}
  529.             bMatch  := System.True;
  530.             dbIndex := 1;
  531.             sSaveBytes[dbIndex] := chInByte;
  532.             dbCount := System.Length(sSearchInput) - 1;
  533.             ddMatchOffsetInFile := gddInOffsetInFile - 1;
  534.  
  535.             WHILE (bMatch) AND (dbCount <> 0) DO
  536.             BEGIN
  537.                _GetByteFromInput(dwInBufOfs,chInByte,dwInByteCount,bInFilePast);
  538.  
  539.                {* special case: EOF detected *}
  540.                IF (bInFilePast)
  541.                  THEN
  542.                    bMatch := System.False
  543.                  ELSE
  544.                    BEGIN
  545.                     System.Inc(dbIndex);
  546.                     sSaveBytes[dbIndex] := chInByte;
  547.                     bMatch  :=  (chInByte = sSearchInput[dbIndex]);
  548.                     System.Dec(dbCount);
  549.                    END;
  550.                {if-then-else }
  551.  
  552.             END;
  553.             {while-do}
  554.  
  555.             {* setup a string length *}
  556.             sSaveBytes[0] := System.Char(dbIndex);
  557.  
  558.             IF  (bMatch)
  559.               THEN BEGIN
  560.                      System.Inc(galiMatchCount);
  561.                      bReplaceMake := System.True;
  562.  
  563.                      IF  (gabUserAskToReplace OR gabUserAskToDisplay)  THEN
  564.                      BEGIN
  565.                          System.Write(asProgramPrompt+'Match found at offset '+achHexPrefix+
  566.                                        +_fnsDoubleWordToHexFmt(ddMatchOffsetInFile)
  567.                                        +'(',ddMatchOffsetInFile,
  568.                                        +')');
  569.                          IF (gabFileToReplace)
  570.                            THEN
  571.                              System.Write(' Replace? (n/y): ')
  572.                            ELSE
  573.                              System.WriteLn;
  574.                          {if-then}
  575.                          IF (gabFileToReplace)
  576.                            THEN
  577.                              System.ReadLn(gsTempInput)
  578.                            ELSE
  579.                              gsTempInput := achUserDontWant;
  580.                          {if-then-else}
  581.                          IF (System.UpCase(_fnchGetFirstChar(gsTempInput)) <> achUserWant)
  582.                            THEN  bReplaceMake := System.False;
  583.                          {if-then}
  584.                      END;
  585.                      {if-then}
  586.  
  587.                      IF  (bReplaceMake)
  588.                          THEN
  589.                            BEGIN
  590.                               dbCount := System.Length(sReplaceOutput);
  591.                               System.Inc(galiReplaceCount);
  592.                               IF (dbCount <> 0) THEN
  593.                                  FOR dbIndex := 1 TO  dbCount DO
  594.                                     _PutByteToOutput(dwOutBufOfs,System.Byte(sReplaceOutput[dbIndex]));
  595.                                  {for-to-do}
  596.                               {if-then}
  597.                            END
  598.                          ELSE
  599.                            BEGIN
  600.                           {* no replacement *}
  601.                              dbCount := System.Length(sSaveBytes);
  602.                              FOR dbIndex := 1 TO  dbCount DO
  603.                                IF (gabFileToReplace)  THEN
  604.                                  _PutByteToOutput(dwOutBufOfs,System.Byte(sSaveBytes[dbIndex]));
  605.                                {if-then}
  606.                              {for-to-do}
  607.                            END;
  608.                      {if-then-else }
  609.                    END
  610.             ELSE BEGIN
  611.                      {* just copy a saved bytes *}
  612.                      dbCount := System.Length(sSaveBytes);
  613.                      FOR  dbIndex := 1 TO  dbCount DO
  614.                        IF (gabFileToReplace)  THEN
  615.                             _PutByteToOutput(dwOutBufOfs,System.Byte(sSaveBytes[dbIndex]));
  616.                        {if-then}
  617.                      {for-to-do}
  618.                    END;
  619.             {if-then-else }
  620.          END;
  621.     {if-then-else }
  622.   END;
  623.   {while-do}
  624.  
  625.   {** output buffer is empty? **}
  626.   IF (dwOutBufOfs <> 0)
  627.     THEN  BEGIN
  628.        IF (gabFileToReplace)
  629.          THEN  BEGIN
  630.          {$I-}
  631.              System.BlockWrite(fOutFile,
  632.                               System.Mem[System.Seg(pOutMemBuf^):System.Ofs(pOutMemBuf^)],
  633.                               dwOutBufOfs,
  634.                               gdwOutBytesWritten);
  635.          {$I+}
  636.          IF (dwOutBufOfs <> gdwOutBytesWritten)
  637.            THEN  BEGIN
  638.             System.WriteLn(asProgramPrompt+'Unable to write output file '+gsOutFileName);
  639.             System.Halt(errDestWriteFailed);
  640.             END;
  641.            {if-then}
  642.                END;
  643.        {if-then}
  644.           END;
  645.   {if-then}
  646. END;  { _ProcessBuffer }
  647.  
  648.  
  649. {*============================== MAIN PART =============================*}
  650.  
  651. BEGIN
  652.   _CopyrightDisplay;
  653.  
  654.      IF (System.ParamCount = 0) THEN
  655.      BEGIN
  656.           System.WriteLn(asProgramPrompt+' help screen for you.');
  657.           System.WriteLn('Usage: infile outfile instr outstr [query]');
  658.           System.WriteLn('  infile   -  source filename       (def. ext. = '+asInDefExt+')');
  659.           System.WriteLn('  outfile  -  destination filename  (def. ext. = '+asOutDefExt+')');
  660.           System.WriteLn('  instr    -  string for search     (the following formats are supported:');
  661.           System.WriteLn('                                       text string (ext. ASCII)   = Hello');
  662.           System.WriteLn('                                       hexadecimal format string  = $0A8D');
  663.           System.WriteLn('                                       text string started with $ = $$world )');
  664.           System.WriteLn('  outstr   -  new string            (see format above)');
  665.           System.WriteLn('  query    -  optional, any string  (user ask for replace)');
  666.           System.WriteLn('                                    (default = no ask)');
  667.           System.Halt(errBadParmsNumber);
  668.      END;
  669.      {if-then}
  670.  
  671.  
  672.   {** copy the parameters from command line **}
  673.   gsInFileName  := _fnsUpcaseStr(System.ParamStr(1));
  674.   gsInFileName := _fnsForceFileNameExt(gsInFileName,asInDefExt);
  675.  
  676.   IF (System.ParamCount > 1)
  677.     THEN  BEGIN
  678.        gsOutFileName := _fnsUpcaseStr(System.ParamStr(2));
  679.        gsOutFileName := _fnsForceFileNameExt(gsOutFileName,asOutDefExt);
  680.           END
  681.     ELSE
  682.       gabFileToReplace := System.False;
  683.   {if-then-else}
  684.  
  685.  
  686.   {* may be same names? *}
  687.   IF (gabFileToReplace)
  688.   THEN
  689.     IF (gsInFileName = gsOutFileName)  THEN
  690.     BEGIN
  691.       System.WriteLn(asProgramPrompt+'Unable to use same file as input and as output');
  692.       System.Halt(errSameNames);
  693.     END;
  694.     {if-then}
  695.   {if-then}
  696.  
  697.  
  698.   {** source file exists? **}
  699.   IF  NOT(_fnbFileExist(gfInputStream,gsInFileName)) THEN
  700.   BEGIN
  701.     System.WriteLn(asProgramPrompt+'Unable to open file '+gsInFileName);
  702.     System.Halt(errSourceNotFound);
  703.   END;
  704.   {if-then}
  705.  
  706.  
  707.   {** destination file present? **}
  708.   IF (gabFileToReplace)
  709.   THEN
  710.     IF (_fnbFileExist(gfOutputStream,gsOutFileName)) THEN
  711.     BEGIN
  712.       System.Write(asProgramPrompt+'Output file '+gsOutFileName+
  713.                    ' already exists. Overwrite? (n/y): ');
  714.       System.ReadLn(gsTempInput);
  715.       IF (System.UpCase(_fnchGetFirstChar(gsTempInput)) <> achUserWant)
  716.         THEN  System.Halt(errDestDontWrite);
  717.     END;
  718.     {if-then}
  719.   {if-then}
  720.  
  721.  
  722.   {** read the following parameter = search string **}
  723.   IF  (System.ParamCount >= 3)
  724.   THEN
  725.     gsTempInput := System.ParamStr(3)
  726.   ELSE
  727.     BEGIN
  728.       System.Write(asProgramPrompt+'Enter search string: ');
  729.       System.ReadLn(gsTempInput);
  730.     END;
  731.   {if-then-else }
  732.  
  733.   _TranslateStr(gsTempInput,gsInSearch,giErrorCode);
  734.    IF  (giErrorCode <> 0)  THEN
  735.      BEGIN
  736.          System.WriteLn(asProgramPrompt+'Invalid format for input string.');
  737.          System.Halt(errBadInStr);
  738.      END;
  739.    {if-then}
  740.  
  741.  
  742.  
  743.   {** read the following parameter = replace string **}
  744.   IF (gabFileToReplace)
  745.   THEN BEGIN
  746.     IF  (System.ParamCount >= 4)
  747.     THEN
  748.       gsTempInput := System.ParamStr(4)
  749.     ELSE
  750.       BEGIN
  751.         System.Write(asProgramPrompt+'Enter replace string: ');
  752.         System.ReadLn(gsTempInput);
  753.       END;
  754.     {if-then-else }
  755.    _TranslateStr(gsTempInput,gsOutReplace,giErrorCode);
  756.     IF  (giErrorCode <> 0)
  757.     THEN  BEGIN
  758.              System.WriteLn(asProgramPrompt+' Invalid format for output string.');
  759.              System.Halt(errBadOutStr);
  760.           END;
  761.     {if-then}
  762.        END;
  763.   {if-then}
  764.  
  765.  
  766.   {** read the following parameter = query switch **}
  767.   IF (gabFileToReplace)
  768.   THEN
  769.     IF  (System.ParamCount >= 5) THEN
  770.     BEGIN
  771.       gabUserAskToReplace := System.True;
  772.     END;
  773.     {if-then}
  774.   {if-then}
  775.  
  776.   IF (gabFileToReplace)
  777.   THEN BEGIN
  778.     IF  (System.ParamCount < 4) THEN
  779.     BEGIN
  780.       System.Write(asProgramPrompt+'Replace by asking? (n/y): ');
  781.       System.ReadLn(gsTempInput);
  782.       IF (System.UpCase(_fnchGetFirstChar(gsTempInput)) = achUserWant)
  783.          THEN  gabUserAskToReplace := System.True;
  784.       {if-then}
  785.     END
  786.        END
  787.     {if-then}
  788.   ELSE BEGIN
  789.       System.Write(asProgramPrompt+'Display offset? (n/y): ');
  790.       System.ReadLn(gsTempInput);
  791.       IF (System.UpCase(_fnchGetFirstChar(gsTempInput)) = achUserWant)
  792.          THEN  gabUserAskToDisplay := System.True;
  793.       {if-then}
  794.        END;
  795.   {if-then-else}
  796.  
  797.  
  798.   {** open the source file **}
  799.   System.Assign(gfInputStream,gsInFileName);
  800.   {$I-}
  801.   System.Reset(gfInputStream,1);
  802.   {$I+}
  803.  
  804.   IF  (System.IoResult <> errOK) THEN
  805.   BEGIN
  806.     System.WriteLn(asProgramPrompt+'Unable to open '+gsInFileName);
  807.     System.Halt(errSrcOpenFailed);
  808.   END;
  809.   {if-then}
  810.  
  811.  
  812.   {** create the destination file **}
  813.   IF (gabFileToReplace)
  814.   THEN  BEGIN
  815.     System.Assign(gfOutputStream,gsOutFileName);
  816.     {$I-}
  817.     System.Rewrite(gfOutputStream,1);
  818.     {$I+}
  819.  
  820.     IF  (System.IoResult <> errOK) THEN
  821.     BEGIN
  822.       System.WriteLn(asProgramPrompt+'Unable to create '+gsOutFileName);
  823.       System.Halt(errDestCreateFailed);
  824.     END;
  825.     {if-then}
  826.         END;
  827.   {if-then}
  828.  
  829.   {** get a count of bytes to read. **}
  830.   gddInByteCount := System.FileSize(gfInputStream);
  831.   gddTotalFileBytes := gddInByteCount;
  832.  
  833.   {** global  var to indicate offset for user **}
  834.   gddInOffsetInFile := 0;
  835.  
  836.  
  837.   {** get memory on heap for input stream **}
  838.   IF  (System.MaxAvail < aMaxOnHeap)
  839.     THEN  gdwInMemBlockSize := System.MaxAvail
  840.     ELSE  gdwInMemBlockSize := aMaxOnHeap;
  841.   {if-then-else}
  842.   System.GetMem(gpInMemoryBlock,gdwInMemBlockSize);
  843.  
  844.  
  845.   {** get memory on heap output stream **}
  846.   IF  (System.MaxAvail < aMaxOnHeap)
  847.     THEN  gdwOutMemBlockSize := System.MaxAvail
  848.     ELSE  gdwOutMemBlockSize := aMaxOnHeap;
  849.   {if-then-else}
  850.   System.GetMem(gpOutMemoryBlock,gdwOutMemBlockSize);
  851.  
  852.  
  853.   {** main loop: read_buffer/process_buffer **}
  854.   WHILE (gddInByteCount <> 0) DO
  855.   BEGIN
  856.       IF  ((gddInByteCount DIV gdwInMemBlockSize) <> 0)
  857.         THEN  gdwInBytesRead :=  gdwInMemBlockSize
  858.         ELSE  gdwInBytesRead :=  gddInByteCount;
  859.       {if-then-else}
  860.  
  861.           BEGIN
  862.                System.WriteLn(asProgramPrompt+'Reading......');
  863.            {$I-}
  864.                System.BlockRead(gfInputStream,
  865.                                 System.Mem[System.Seg(gpInMemoryBlock^):System.Ofs(gpInMemoryBlock^)],
  866.                                 gdwInBytesRead,
  867.                                 gdwInBytesReadTest);
  868.            {$I+}
  869.            IF (gdwInBytesRead <> gdwInBytesReadTest)
  870.            THEN  BEGIN
  871.             System.WriteLn(asProgramPrompt+' Unable to read input file '+gsInFileName);
  872.             System.Halt(errSrcReadFailed);
  873.             END;
  874.            {if-then}
  875.                System.WriteLn(asProgramPrompt+'Processing...');
  876.                _ProcessBuffer(gfInputStream, gpInMemoryBlock, gdwInBytesRead,gdwInBytesRead,
  877.                               gfOutputStream,gpOutMemoryBlock,gdwOutMemBlockSize,
  878.                               gsInSearch,gsOutReplace,gdwInBytesReadAdd);
  879.                System.Dec(gddInByteCount,gdwInBytesRead+gdwInBytesReadAdd);
  880.                System.WriteLn(asProgramPrompt+'Completed (',System.Trunc(((gddTotalFileBytes-gddInByteCount)
  881.                               /gddTotalFileBytes)*aPercent100),'%)');
  882.  
  883.           END;
  884.   END;
  885.   {while-do}
  886.  
  887.  
  888.   {** close all files **}
  889.   System.Close(gfInputStream);
  890.   IF (gabFileToReplace)
  891.   THEN
  892.     System.Close(gfOutputStream);
  893.   {if-then}
  894.  
  895.  
  896.   {** free memory on heap **}
  897.   System.FreeMem(gpInMemoryBlock,gdwInMemBlockSize);
  898.   System.FreeMem(gpOutMemoryBlock,gdwOutMemBlockSize);
  899.  
  900.  
  901.   {** put newline char and write report**}
  902.   System.Write(asProgramPrompt+'Matches found = ',galiMatchCount);
  903.   IF (gabFileToReplace)
  904.   THEN
  905.      System.WriteLn(',  Replaces made = ',galiReplaceCount)
  906.   ELSE
  907.      System.WriteLn;
  908.   {if-then-else}
  909.   System.WriteLn(asProgramPrompt+'Done.');
  910.  
  911.   {* System.Halt(errTerminateOk); *}
  912. END.
  913.