
Writing patch definitions for !Patch.
-------------------------------------
It is recommended that any patch files supplied seperately from !Patch be
neatly bundled into an application directory which Filer_Runs them all for
you when you double click on it. In this way a path variable can be set up
for the directory, allowing unambiguous yet directory and filing system
independent file paths to be quoted for accessing other patch files,
transform files and *commands.

Directory verification.
-----------------------
When writing patch files, you should remember that !Patch needs to be able
to verify that the correct application directory is being dealt with. So
for example the sole purpose of the patch may be to put a !Sprites22 file
into the application directory, but this will not be sufficient for
!Patch to be certain that it is patching the correct directory. The best
way is to specify some words in the !RunImage that !Patch can verify. It
will then only move the !Sprites22 file in if the words in the !RunImage
match.

There should always be some words, bytes or strings in a patch that
actually change (or a file which is created or deleted). If not, !Patch
cannot tell the difference between a directory which has had the patch
applied to it and one which has not. This is not a particularly great
restriction - there is always a version number in some file or other
that should be modified anyway.

File extension.
---------------
It is possible to extend the file being patched, simply by specifying
ChangeWord commands which are off the end of the file. In this case, the
old bytes should be specified as &00.

Patch file format.
------------------
The BootStrap patch file inside !Patch is read on startup, which causes the
patch files stored inside the Patches sub-directory to be read. Patch files
should have a filetype of Patch (&FC3). Files with any other filetype will
be ignored.

The patch files are textual in nature. Each line of a patch file can
be one of:

    blank
    start with a # to be a comment line
    of the form Command:other parameters

Blank and comment lines are ignored.
Other lines have the following meanings:

PatchesDir:<file or directory path>
This causes the path specified to be recursively scanned for more patch
files. This is typically used so that you only have to Filer_Run one
patch file (eg. Filer_Run MyPatch:StartUp) in your !Run file to get
!Patch to automatically find all the patch files in the directory
specified.
eg.
PatchesDir:Patch:Patches

TransformsFile:<file path>
This adds the file specified to the list of files looked in to build the
*commands for performing transformations.
eg:
TransformsFile:Patch:Transforms

Application:<program name> <file type>
This introduces some patches for the named application.
eg:
Application:!PCEm &2000

Description:<program description>
This is a textual description of the application.
eg:
Acorn PC Emulator

Patch:<patch name>
This introduces a patch and gives it a textual name. This name will be what
is quoted in the patch query window.
eg:
Patch:Fix bug in version 1.60 with DOSDisc hard disk images

File:<file name> <file type>
This introduces some patches for the named file in the application. Note
that the file name quoted should always start with the application directory
- this allows individual files to have patches for them.
eg:
File:!PCEm.!RunImage &FF8

Transform:<transform>
This optional field indicates that the file has had the named transform
applied to it. The patches will be applied to the untransformed form of
the file. A list of default transforms can be found in the Transforms
file of !Patch. Currently this is Squeeze, and do nothing (Copy).
eg:
Transform:Squeeze

Location:<location>
This indicates the byte location in the unsqueezed (or whatever) file for
the following changes. To specify in decimal just give the number. To
specify in hex prefix the number with an &. The location is always in the
unpatched file. Where the patched file ends up with a differentlength,
appropriate adjustments are made to the location in the target file.
Effectively this means that two locations are maintained.
eg:
Location:&1B2D0

ChangeWord:<from> <to>
This describes the change required to a single word at the current location.
Location advances by four each change, so you may give a sequence. The
current location should be word aligned (a multiple of four) when this
keyword is specified.
eg:
ChangeWord:&059D0008 &13500003
ChangeWord:&028DD010 &13A00000
ChangeWord:&13A00000 &059D0008
ChangeWord:&128DD010 &E95BA800

VerifyWord:<word>
This specifies that the word at the current location must match the word
specified. The locations are advanced by four.
eg:
VerifyWord:&54230001

ChangeByte:<from> <to>
This describes the change required to a single byte at the current location.
Location advances by one each change, so you may give a sequence.
eg:
ChangeByte:&BD 65

VerifyByte:<byte>
This specifies that the byte at the current location must match the byte
specified. The locations are advanced by one.
eg:
VerifyByte:&23

ChangeString:<from> <to>
This describes the change required to a string at the given location.
<from> and <to> must be of the same length, and are in GSTrans format.
The strings must not contain spaces, as space is the seperator between the
two strings. Use <32> instead of space. The current location advances by
the length of the strings, so you may give a sequence.
eg:
ChangeString:Verify<32>:4|M Verify<32>4|M<0>

VerifyString:<string>
This specifies a string which must match the string found at the current
location. The locations are then advanced by the length of the string.
eg:
VerifySring:<127>foobar<32><0>

ReplaceFile:<file name>
OldContents:<file name> <file type>
NewContents:<file name> <file type>
This causes the file in the application directory to be replaced with a
new version of the file supplied within the patches directory. The old
version of the file is also supplied in the patches directory to allow
patch removal. No checking of the file contents is performed, so you
should ensure there is enough verify or change data for other files in
the application to allow !Patch to be certain it is dealing with the
correct directory eg. verify some words in the !RunImage. You may use
verify data for the file to be replaced, so for example you could verify
the comment string at the start of a !Run file since that is unlikely to
have been edited by the user. If you do this, the data verified must be
present and correct in both the OldContents file and the NewContents file.
eg:
ReplaceFile:!PCEm.!Boot
OldContents:Patch:Files.Acorn.PCEm.Old.!Boot &FEB
NewContents:Patch:Files.Acorn.PCEm.New.!Boot &FEB

CreateFile:<file name>
NewContents:<file name> <file type>
This causes the file in the application directory to be created, its
contents being taken from the file specified in the patches directory.
eg:
CreateFile:!PCEm.!Sprites22
NewContents:Patch:Files.Acorn.PCEm.New.!Sprites22 &FF9
CreateFile:!PCEm.!Sprites23
NewContents:Patch:Files.Acorn.PCEm.New.!Sprites23 &FF9

DeleteFile:<file name>
OldContents:<file name> <file type>
This causes the file in the application directory to be deleted. Its
contents are provided to allow patch removal.
eg:
DeleteFile:!PCEm.!Boot
OldContents:Patch:Files.Acorn.PCEm.Old.!Boot &FEB

Transforms file format.
-----------------------
The transforms files are processed using MessageTrans. The tokens looked up
for a given transform are <transform>_Prepare and <transform>_Finish to get
the actual *commands, and <transform>_PrepareSlot and <transform>_FinishSlot to get the Wimp slot size (in K) that each command gets to start with. The
documentation for the transforms is here rather than in the Transforms
file as MessageTrans reads the entire of the Transforms file into memory,
comments and all.

For <transform>_Prepare, %0 is the initial file and %1 is the file that
will actually be patched.

For <transform>_Finish, %0 is the patched file and %1 is the final file.

In both cases, %2 is a filename that printed output from the transforming
program should be redirected to. For a program that does not print anything
(eg. UnSqueeze) it need not be specified. After the transformation
program has been run, if the error file exists and is of non zero size its
contents will be displayed in an error box. !Patch will then attempt to
continue ie. it is not assumed that the presence of output means an error
occured. In fact in the case of squeeze, if there is any output there
was an error, and !Patch will get a "File not found" error when it attempts
to continue.

After SWI MessageTrans_GSLookup has been called, the results should be
a valid *command which will perform the job, which is passed to SWI
Wimp_StartTask. This may of course be an Obey file. Application space
may be used however you like, as the *command is running as a new wimp
task with its own application space.

The Prepare transformation is exercised a lot. Not only is it used while
performing the actual patching but it is also used while scanning
directories and after patching has been performed to work out whether
the patches for a file can be applied, removed, or neither. Therefore
the prepare transformation should ideally be fast, small and memory
resident eg. UnSqueeze is performed by a small module loaded by !Patch.!Run.
The benefit of being memory resident is that you have to swap floppy disks
much less often. The benefit of being small is that you can afford to be
memory resident. Squeeze takes a lot of memory to run, so you should not
rmload huge modules just so you can have memory resident prepare transforms
as this may then mean there is insufficient memory for Squeeze to run
when a particularly large file is patched eg. !DTP.!RunImage.

'Copy' is the standard "transform" used for files which need no
transforming. This is because we patch in <Wimp$Scrap> and the transform
performs the copying operations.

'Squeeze' is the transform used for programs which have been run through
the squeeze program supplied with the Acorn C and Assembler packages.

eg:
Copy_PrepareSlot/Copy_FinishSlot:8
Copy_Prepare/Copy_Finish:Copy %0 %1 ~A ~C ~D F ~L ~N ~P Q ~R S ~T ~V

Squeeze_PrepareSlot:0
Squeeze_Prepare:UnSqueeze %0 %1
Squeeze_FinishSlot:32
Squeeze_Finish:Run Patch:Library.squeeze %0 %1
