replace - The ChangeLog

Here's a list of changes I've made to replace since it was released about 10 years ago (apologies for the pre-formatted text, but it's how I keep the original info)...

replace 2.24 (October 2004)

* Corrected a comparison of two size_t's that were underflowing and causing
  a crash due to unallocated memory being accessed during string replacements
  in text files.
* One of the tests in the new test suite assumed that the user's PATH contained
  ".", which often isn't the case (particularly for root). This has been fixed.
* The "-A" option is deprecated in this release. It will either change its
  functionality (unlikely) or be removed (more likely) in a future release
  and hence should not be used any more. The reason for this is that it's
  too "dangerous" (can potentially damage binary files) and the current code
  isn't easily changed to make it less risky.

replace 2.23 (September 2004)

* Added a new -d parameter to specify which (temporary) directory
  modified files are written to (falls back to $TMPDIR or /tmp if -d
  isn't supplied).
* If a text file has only one line and that line has no linefeed (\n)
  terminator, then that single line is now correctly read in and parsed
  (it used to be incorrectly ignored in previous releases).
* If a text file has a string replaced in a line which has no linefeed
  terminator (by definition, this must be the last line in the file of course),
  then a linefeed is no longer added to the end of that replaced line.
* Avoid crash if -A is supplied and a binary file containing null bytes (ASCII
  code 0) is specified. This will *still* corrupt the output file, so a
  second warning about the -A option (i.e. don't use it unless you're
  certain all files are text files) was added to the man page as well.
* If fdopen() fails during the creation of a temporary file, that file
  is now correctly closed and deleted.
* Keep a global track of the name of the current temporary file (or ""
  to mean no temporary file active).
* The tidy_up routine (run on program exit) will now remove the current
  temporary file if one is active.
* Trap signals (e.g. SIGINT) and run the tidy_up routine. This finally means
  that, unlike "rival" string replacement programs, CTRL-C will no longer
  leave a temporary file behind.
* A new test suite has been written - "gmake test" now runs a shell script
  that puts the built replace binary through its paces. A more verbose
  version can be run with "gmake verbosetest".
* Ran the code through "splint" (Linux lint) and fixed the warnings.
* Updated FEATURES file to allow for GNU sed 4.X (a couple of marks extra
  for that compared to 3.X) and also added MySQL's replace (yes, there's a
  binary name-clash there with this program and I've told MySQL about that...).

replace 2.22 (May 2004)

* Support for signed long long added (including use of %lld for output of
  such 8-byte integers) - falls back to signed long if signed long long
  isn't available.
* Double-quoted source and destination files if mv binary used to rename
  files in the rename_files() routine. This should allow files with spaces
  in their name to be correctly renamed.
* Compiled with flags to support 64-bit file offsets/large files.
* Documented -P option in "replace -?" output.
* Fixed old and new string comparison when -h is used - memcmp() instead
  of strcmp() is needed of course because the hex strings can contain
  binary 0 in the middle of them, which thwarts strcmp().
* Minor changes to fix +w1 warnings with HP-UX 11.23's paranoid HP ANSI C
  compiler (most +w1 warnings now come from HP-UX's own system header
* Added note about shell special characters such as brackets in the man
  page (i.e. you need to single or double quote params if they include
  any special char).
* Confirmed that replace builds with a K&R-only C compiler ("cc_bundled"
  that comes as standard with HP-UX 11.00) as well as an ANSI C compiler.

replace 2.21 (March 2004)

* Fixed incorrect assumption that a char was an unsigned byte (it's
  actually a signed byte) - this was causing binary replacements to crash
  on occasions.
* Switched to using mkstemp() instead of tmpnam().
* Added .xhtml and .shtml extensions to those picked up by the -w flag.
* Makefile now requires GNU make and will auto-detect Linux or HP-UX flags
  as necessary.

replace 2.20 (June 2001)

* New auto.c source file added the auto-detection of binary files (turned
  on by default). At long last, a mixture of binary and text files can be
  supplied on the command line and replace will use the first 256 bytes
  of each file to determine if the file is text or binary automatically.
  Note that other string replacement programs such as sed or rpl actually
  corrupt binaries when they are run with different-sized old and new
  strings (by shifting all the data, making the binary fail to run),
  whereas the replace command avoids this.
* New FEATURES file to provide a feature-by-feature comparison chart between
  sed, rpl and replace. Guess who wins ? :-)
* Added new "-A" option to force replace to think all supplied files are
  text files (i.e. it turns off the new auto-detection code and reverts to
  the default text file replacement mode of previous releases). It's probably
  not a good idea to use this option, because there is a risk of corrupting
  any binaries that are specified.
* Added new "-P" option to pre-pad any new replacement string with leading
  spaces (as opposed to -p, which pads with trailing spaces).
* Verbose mode (-v) now has two levels - a single -v only displays a summary
  about files that had replacements performed on them. Two -v's (e.g. -vv)
  reverts to the older behaviour of showing all the replacements that take
  place and providing an overall summary. This means that replacing
  a large number of files (especially with -r) and using a single -v won't
  swamp the screen with output. -i and -n now also "double up" and increment
  the verbosity level to match the number of times they are specified.
* If the directory containing a file to be modified was read-only, then
  the update of the file used to fail silently. This has been fixed - a
  warning message is sent to stderr now.
* Missing break statement in the '-T' option parsing caused problems on
  some systems - it's now been fixed.
* The old string to be replaced can now be null (i.e. ""), but only when
  doing replacements in text files of course. It replaces blank lines with
  the new string specified.
* Zero-length files are now detected and skipped with an appropriate warning
  (you can't do replacements on totally empty files, because there's not
  even a blank line to replace !).
* Now use a function instead of a macro to copy characters into the new line
  buffer when doing replacements on text files. This reduces the overall
  code size by not replicating the same macro code 8 times.

replace 2.10 (June 2001)

* Added new "-T" option to retain the original timestamp of modified files
  (I don't think this should be the default, because the changed timestamp
  gives you a clue if the file has been modified or not, especially if you
  use -f and don't have a backup to compare it with).
* Added new "-L" option to follow soft-links supplied on the command-line
  before doing replacements (potential soft-link loops and relative soft-links
  containing ".." are both coped with). The default is now to ignore such
  soft-links and issue a warning (which is actually a bug fix compared to
  previous behaviour when replace came across a soft-link).
* Any filename parameter that isn't a directory (-r or -w needed),
  file or soft-link (-L needed) is now ignored with an appropriate warning.
  This prevents "sillies" like FIFOs and device files being supplied.
* You can now optionally specify directories to recurse down when -r
  is supplied (if none are stated, the current directory is recursed).
  You can still mix files and directories on the command line with -r of
  course (like the way you can with "rm").
* Added prototypes if an ANSI C compiler is used, which finally removed all
  HP ANSI C compiler warnings with the +w1 flag (so that's now been added
  to the flags for that compiler). Prototypes that cover calls from multiple
  source files have been moved into replace.h, whilst if only one source
  file calls a prototyped routine, it's put in the source file.
* Added .asp, .js, .css, .xml, .jsp, .php, .php3, .php4 and .pl to the
  list of extensions detected by the "-w" option.
* The -x suffix checking is now case-insensitive.
* Display "6" through to "9" as words ("six" through to "nine") in verbose
  messages in addition to the 0-5 that the previous version displayed as words.
* Verbose mode now displays "...binary file..." or "...text file..." messages
  depending on whether -b was specified or not.
* Verbose mode now displays "line y, column x" output when replacing, which is
  a little better than "pos: x, line: y".
* Added use of ferror() to check for read/write/close errors when accessing
  files. Any file with such an error will not be updated and will be skipped.
  If stdin/stdout operations have an error, the program is aborted.
* Fixed bug that wasn't closing original text file when "replace -n" was used.
* All warning messages now have a "WARNING:" string at the start (most already
  did, but some didn't).
* All malloc() routines are now checked for failure and the program will abort
  if it can't allocate memory at any time.
* Used lint to tidy up ultra-pedantic cross-source warnings.

replace 2.01 (February 2000)

* No memory was malloc()'ed when the first line of a file was blank (should
  have malloc()'ed 1 byte), so when a zero-terminator was stored for the
  replaced string, the code would crash intermittently. This has been fixed.
* New Web site for replace:

replace 2.00 (November 1999)

* New binary.c source file to cope with binary-related code.
* New init.c source file containing initialisation routines.
* New text.c source file containing text-related code.
* Variables now global and moved into replace.h.
* Added "-b" to signify that all input files are in binary format and should
  have binary replacements rather the default line-based string replacements.
* Added "-h" to specify the replacement binary strings in hex.
* Added "-m" to indicate the maximum number of lines in a file that
  should have replacements.
* Added "-t" option to state the maximum number of times a string can
  be replaced in any single line of a file.
* Added "-z" option (to be used with -b) to zero-terminate strings that are
  shorter when replacing such strings in binaries (by default it doesn't).
* Memory for file buffers is now dynamically allocated, so there's no
  more nasty string truncation of very long lines any more.
* All functions now have at least one comment.
* Added ident string so that "what replace" reports the version info.
* Sizes of the original and replaced files are now output in verbose mode.
* Fixed problem with GNU getopt() re-ordering the minus options (causing
  -a not to be parsed properly). I added a "+" as the first char of the
  getopt() options param and this cured the problem.
* Man page, usage output and getopt() qualifiers all now sync with each
  other (unlike the previous release).
* Added some useful examples to the man page.
* Syntax message now uses argv[0] (and auto-adjusting option indentation) to
  display the binary name.
* Now tested on HP-UX 10.20, HP-UX 11.00, Solaris 2.6 and Linux.
* Announced to for the first time (since no-one seems to
  know of the existence of "replace" !).

replace 1.10 (October 1999)

* Added a "-i" option to interactively prompt the end-user.
* Added "-n" to just show what strings would be replaced without actually
  replacing them.
* Added a "-r" option to recurse the current directory.
* The "-u backupsuffix" option now allows the user to choose their own
  backup suffix (the default of .cln might seem strange to some people).
* Added "-w" option to allow easy string replacement of an entire Web tree's
  HTML documents.
* Added a "-x suffix" option to combine with -r in only replacing strings
  in files that end in the specified suffix.
* Increased maximum string length before truncation from 1023 to 4095 chars.
* Added a "make test" rule.
* Added a "make gcc" rule for my own convenience rather than anyone else's :-)
* Supplying no params at all now displays the Usage message.
* Various other small improvements to the code (nothing user-visible).
* Deleted text2html and text2html.1 - not worth including (there are much,
  much better text to HTML converters out there - this was one was very
* Deleted patchlevel.h and merged its content (yep, one line with the
  version number in it) into replace.h. Never saw the point of patchlevel.h
  myself - I only did it because a few other packages pointlessly used it.

replace 1.03 (June 1998)

* Updated files now retain their original permissions, ownership and group
  where possible. The datestamp is modified of course though because the file
  contents have been changed.

replace 1.02 (April 1996)

* Added "-c startcol" to start string replacements from a particular column.
* Check for line length after replacements and truncate it if it exceeds
  1023 characters.
* Bug fix to case-matching routine.
* Bug fix to "-a" checking.
* Picked up program name from argv[0] and used in error messages.
* Added verbose-mode message to indicate start column and line for the
* Don't display syntax guff unless "replace -?" or a bad replace qualifier
* Added a text2html.1 man page.
* Separated definitions and includes into replace.h.
* Slight modification of Makefile to install into /opt/replace tree for
  PD archive 10.X package [no changes to any other source files for the 10.X
  source package of replace 1.02].

replace 1.01 (1995 ?)

* Added "-a old_str new_str" to finally bury the ghost of sed once and for all.
* Added "text2html" script to show off the new -a option :-)
* Fixed a bug w.r.t. the temporary file not getting deleted.
* Kept "make lint" happy.
* Added "patchlevel.h" complete with version number.

replace 1.00 (1994)

* Initial release - probably the first ever string-replacing program that could
  keep the (possibly mixed) case of the original string when replacing it with
  a new string. This is a very useful thing - after all, not everything is all
  in lower or upper can be mixed too. This was always a major
  frustration for me when using sed (apart from the dreadful sed syntax of