Invoking the patch tool

Usage:

    rochay  [-vta] [-o newFile]  fileToPatch  patchCmdFile  [script args]

where -v causes rochay to recite its results from both the verification pass and the application pass.

-t prevents rochay from actually applying any changes, implies -v, and otherwise does everything except modify the file.

-o specifies the name of an alternate output file to write the patch results to. Implies no replacement of the original file.

-a reverses the sense of the comparison command (?).

fileToPatch is the name of the file whose contents are modified by rochay. If the fileToPatch is supplied via the (|) command within the patch command file, use (-) as a place-keeper here.

patchCmdFile specifies the name of the file containing the patch commands to apply to the fileToPatch.

[script args] may be any legal patch commands, but typically names a macro to invoke within the patch command file.

Each command line token, beginning with [script args], is assigned to a script macro: %cliN, with N running from 1 to the total number of script arguments.

In addition, the entire set of script arguments is raveled into a single string and assigned to the macro %cli. So the specimen:

    rochay fall.exe items.pat %stamina %identify

creates three macros for the patch script:

	"cli1
	%stamina
	"
	"cli2
	%identify
	"
	"cli
	%stamina %idenify
	"

If the patch script contains the command %cli1, the %stamina macro will be performed. In this example, %cli isn't meaningful.

Each line of the patch script is scanned for shell symbols to replace with values taken from the current environment table. $name indicates the current value for name should be retrieved from the environment table. If there is no entry for name in the table, the empty string will be substituted.

Each line of the patch script is scanned for patch symbols to place with values taken from the current macro or command line invocation. %name indicates the current value for name should be retrieved. If there is no corresponding value, the empty string will be used.

Replacement is not recursive, so if name itself resolves to another symbol, that text will be used verbatim; no further symbolic evaluation will occur.


Patch scripting language

Each line of the patch command file is divided in two. The first part gives the patch command, while the second gives the data which the command operates on.

The language uses the notion of a dot to symbolize a position within the file to be patched.

Numbers may be expressed in the decimal base in the usual way, e.g. 11. Or in the hexadecimal base with the leading prefix "0x", e.g. 0x0b. Or in the octal base with the leading prefix "0", e.g. 013.

Command specifications

	-
Introduces a comment record. Must begin in column one.

	.
Make dot the last offset used previously.

	.pure number
Make dot the specified file offset.

	=pure number
Assign the table increment value. The pure number may be unqualified, which implies the table count field size is one byte. Or it may be qualified by s to indicate a 16 bit size, or by l to indicate a 32 bit size.

The %from macro can be used to iterate over (and machinate) a range of offsets comprising the table within the file to be patched.

	=+
Apply the table increment value to the file offset given by the data specification. The file offset may be expressed relative to the current dot position by using a signed number.

	pure number
0-based file offset to begin replacing bytes with those supplied by the data part of this command.

	+
Continue replacement from the last offset referenced, using the data part of this command.

	+pure number
File offset relative to the latest dot command to begin replacing bytes with those supplied by the data part of this command.

	-pure number
File offset relative to the latest dot command to begin replacing bytes with those supplied by the data part of this command.

	?pure number
	Error message
0-based file offset whose contents must match the data specification. If the match fails, print the contents of the next script record and die, else skip the next script record.

The -a switch inverts the sense of the compare so that a match issues the death notice. Useful for an update patch to detect that its progenitor is already installed. Note that -a applies to all (?) operations.

	<pure number
Permenantly eliminate a number of bytes from the file, beginning at the specified file offset. The data specification gives the number of bytes to exclude in this case. This decreases the the overall size of the patched file.

	>pure number
Insert the data specifications before the original data at the specified offset. This expands the overall size of the patched file.

	>>
Insert the data specifications after the last byte in the original file.

	<+
Continue deleting from the last offset.

	>+
Continue inserting from the last offset.

	@pure number
0-based file offset to begin replacing with bytes copied from the data specification offset. The data spec offset must be followed by a byte count: @17 0x444 15. The file offset must be expressed by absolute value.

	"macroName
	 def1
	 def2
	  :
	  :
	"
Defines a named macro composed of a number of script commands, def1, def2, etc.

	%macroName parm1 parm2 ...
Invokes macroName with parameters parm1, parm2, etc. Within the body of the macro definition, the first parameter may be retrieved by %mac1, the second by %mac2, and so forth.

	^fileName
Include the commands from fileName verbatim.

	<^fileName
Insert the whole byte stream from fileName at dot (.)

	|sourceFile|destFile
Mark a section in the patch file to edit the sourceFile and optionally produce a separate destination file. If sourcefile does not exist, rochay will terminate.

	!sourceFile!
Like (|), but allows the new source file to be created, instead of dying on error. rochay normally terminates if the file-to-be-patched doesn't exist. Only makes sense in the context of a patch which consists wholely of inserts.

Range iteration

	%from  startingOffset  finishedOffset

The reserved macro name %from performs an iteration over a range of file offsets. Use the =nnn command to define the interval step size.

    =6l
    %from 2 0x2106

steps through the file from offset 2 to 0x2106 at six byte intervals. (The length modifier to (=) does not affect the step size)

Note that only one %from macro may be defined at a time. Note that iterations may not be nested.

Count iteration

	%iterate count

The reserved macro name %iterate performs an iteration the specified count number of times.

Note that only one %iterate macro may be defined at a time. Note that iterations may not be nested.

Data specifications

	pure number
the byte value replacement, count, or offset. Replacement values can be suffixed to override the default destination size of 1 byte by using s (short, or 16 bit integer), m (medial, or 24 bit integer), or l (long, or 32 bit integer). This eliminates the need to burst large integers into byte-size values for machination.

	n:m
the texture.nnn picture m value to insert (s or 16 bit integer implied). So 184:3 indicates the 4th picture (numbering from 0) in texture.184.

	"foo"

the string value replacement. There is no separate escape for embedded quotes within a string value, so use the alternate quoting scheme to embed a quote mark.

	'foo'

the string value replacement. There is no separate escape for embedded quotes within a string value, so use the alternate quoting scheme to embed a quote mark.

	whitespace

delimiter between consecutive data values.

	n * data

Repeat data pattern n times.


General remarks

The user specimen:
	0x11	11 0x14 "some foo"  4 * 0  2 * "   "
results in the substitution:
	0x0b 0x14 s o m e 0x20 f o o 0 0 0 0 0x20 0x20 0x20 0x20 0x20 0x20
beginning at the 0-based offet 17 (0x11) in the file to be patched.

Patching proceeds in two passes.

Pass one polices the patch command stream for idiocies before attempting any file modifications.

Pass two applies the changes specified by the patch command stream.

If there are no insert (>) or delete (<) commands, the file is updated in place; no copy is created, unless overridden by (|).

If insert or delete processing is required, a byte-for-byte copy of the original is created, applying the insert/delete requests as required along away. After successfully changing the file, the original is replaced with the modified contents, unless overridden by the (|) command or the -o comand line switch. The file system containing the file to patch must have sufficient free space to accommodate both the original and its edited copy or the patch will fail spontaneously.

Note the purpose of verification commands is to determine whether to start patching at all, or not. This tool expects all verifications will be performed before any modifications are attempted. Circumventing this heuristic can cause the patch to fail spontaneously in novel and wicked ways. This is especially true if the insert/ delete series of commands are used.

The patch command file may be sectioned to cover different sets of patched files with one script.

	|fileToPatch|patchedFile

lines delimit areas of the script. Script lines subsequently apply to the fileToPatch / patchedFile pair. The next (|) command or the end-of-file delimit the applicable commands.

Note that intervening blanks within the pair of (|) symbols will be included as part of the requested file name.

Note that for sectioned scripts, verification covers all the proposed changes to all the files before any modifications commence.

If a fileToPatch is given on the invocation command line, this implies an unwritten (|) command as the first operation of the patch script. Subsequent (|) within the script can delimit that scope of operation.


Copyright © 2001, Nagual Enterprises