General rules:

	*-index
		<path><tab><tag>
		sort -k 2




,,mod-file-index-by-name
,,mod-dir-index-by-name
		<mod-name><tab><tag>
		sort -k 1

		modified tree indexes sorted by name

,,tree-dir-index
,,tree-file-index
		<tree-name><tab><tag>
		sort -k 2

		inventory of tree before applying patch


,,removed-files-index
,,missing-removed-files-index
		<tree-name><tab><tag>   -- ,,removed-files-index
		<orig-name><tab><tag>   -- ,,missing-removed-files-index
		sort -k 2

		inventory of removed files


,,renamed-files
		<orig-name><tab><mod-name>
		sort -k 2

		files renamed by patch


,,renamed-file-ids
		<tag>
		sort

		ids of files renamed by patch


,,missing-renamed-files-index
		<orig-name><space><tag>
		sort -k 2

		files renamed by patch missing from tree


,,renamed-dirs
		<orig-name><tab><mod-name>
		sort -k 2

		directories renamed by patch


,,renamed-dirs-ids
		<tag>
		sort

		ids of dirs renamed by patch


,,renamed-dirs-index
		<tree-name><space><tag>
		sort -k 2

		dirs renamed by patch that are present in tree


,,missing-renamed-dirs-index
		<orig-name><space><tag>
		sort -k 2

		dirs renamed by patch missing from tree


,,removed-dirs-index
		<tree-name><space><tag>
		sort -k 2

		dirs removed by patch that are present in tree


,,missing-removed-dirs-index
		<orig-name><space><tag>
		sort -k 2

		dirs removed by patch that are missing from tree

,,shuffled-dirs-temp-names
		<tree-name><tab><counter>
		sort -r -k 1

		dirs in tree removed or renamed by patch, 
		sequentially numbered from 0

,,shuffled-dirs-new-names
		<mod-name><space><counter>
		sort -k 2

		renamed dirs that were in tree, then in the
		shuffle area, each named by its counter

,,shuffled-removed-dir-names
		<tree-name><space><counter>
		sort -k 1

		removed dirs that were in tree, then
		in the shuffle area, each named by its counter

,,needed-new-directories
		<mod-name>
		sort

		modified-only-dirs not initially present in tree

,,install-dirs-plan-raw
		<mod-dir>/<space><mod-tail><space>   c     <space><mod-name><space> --
		<mod-dir>/<space><mod-tail><space><counter><space><mod-name><space><tag>
		         1	     2               3		      4              5
		sort -k 1 -k 2		

		new ("c") and renamed ("counter") directories that
		will be added (back) to the tree

		<mod-dir> is not empty (first component is always ".")

,,dirs-moved-in-tree
		<mod-name><tab><tree-name>
		sort -k 1 -k 2

		dirs in tree that aren't where they were in mod

,,dirs-moved-sed-script
		s:^<mod-name>/:<tree-name> :
		t

		last line:
		s:^:. ./:

		the ,,dirs-moved-in-tree list,
		sorted by mod-name, then tree-name


,,install-dirs-plan-cooked
		<tree-dir><space>./<rel-path><space><tail><space>    c    <space><mod-name><space>      --
		<tree-dir><space>./<rel-path><space><tail><space><counter><space><mod-name><space><old-tree-name>
		     1		       2	      3              4               5                   6
		sort -k 2

		The ,,install-dir-plan-raw list with prefix paths of
		<mod-dir> that are already in <tree> (under a
		different name) split into the tree part and the
		left-over part.

		In other words, the goal is to install <mod-name> in
		tree, but <mod-name> is:

			<mod-prefix>/<rel-path>/<tail>

		and <mod-prefix> already exists in tree, either as the
		root ("./") or under a different name.  The dir really 
		goes at:

			<tree-dir>/<rel-path>/<tail>


,,needed-new-files-raw
		<mod-dir>/<space><mod-tail><space><mod-name>
		sort -k 3

		Files new in mod, not present in tree.

,,needed-new-files-cooked
		<tree-dir><space>./<rel-path><space><tail><space><mod-name>
		    1			2	      3		     4
		sort -k 4

		Files new in mod, not present in tree.  Files are in
		mod as <mod-name> but go in tree as:

			<tree-dir>/<rel-path>/<tail>

,,needed-new-files-script
		cp -p "$delta/new-files-archive/<mod-name>" \
		      "$tree/<tree-dir>/<rel-path>/<tail>"

		Derived trivially from ,,needed-new-files-cooked

,,install-dirs-soft-conflicts
		For each line of ,,install-dirs-plan-cooked, several
		lines:
			<tree-dir>/<rel1>
			<tree-dir>/<rel1>/<rel2>
			<tree-dir>/<rel1>/<rel2>/<rel3>
			...

		For each new dir line ("c", not <counter>), also:

			<tree-dir>/<rel-path>/<tail>

		sort -r -u

		These are files that should become .rej files
		and cause a conflict when new and renamed dirs are
		installed, if they exist but are not directories.
		Sorting gives deepest to shallowest for nested dirs. 

,,install-dirs-hard-conflicts
		For each rename line (<counter> not "c") of
		,,install-dirs-plan-cooked:

			<tree-dir>/<rel-path>/<tail>

		sort -r -u

		These are files that should become .rej files
		and cause a conflict when new and renamed dirs are
		installed, if they exist (directories or not).
		Sorting gives deepest to shallowest for nested dirs. 



,,install-dirs-script
		For each "c" line of ,,install-dir-plan-cooked:

			mkdir -p "<tree-dir>/<rel-path>/<tail>"

		For each <counter> line:

			mkdir -p "<tree-dir>/<rel-path>"
			mv "$tmpdir/shuffled-dirs/<counter>" \
			   "<tree-dir>/<rel-path>/<tail>"

                where sorting is from shallow-to-deep for nested dirs

		Where <rel-path> is empty, just <tree-dir>/<tail> is
		used.

,,removed-dirs-script
		For each line of ,,shuffled-removed-dir-names

		mkdir -p "$tree/++files-removed.../`dirname \"<tree-name>\"`" 
		mv "$tmpdir/shuffled-dirs/<counter>" \
		   "$tree/++files-removed.../<tree-name>"

		where sorting is from shallow-to-deep for nested dirs

,,renamed-files-plan-raw
		<mod-dir>/<space><mod-tail><space><mod-name>
		sort -k 3

		Renamed files that were in tree, then in 
		$tmpdir/renamed-files under their old tree names.

,,renamed-files-plan-cooked
		<tree-dir><space>./<rel-path><space><tail><space><mod-name>
		    1		       2	       3	     4
		sort -k 4

		The renamed file that is <mod-name> in mod belongs at:

			<tree-dir>/<rel-path>/<tail>

		in tree.

,,install-files-soft-dir-conflicts
		For each line in ,,renamed-files-plan-cooked and
		,,needed-new-files-cooked, several lines:

			<tree-dir>/<rel1>
			<tree-dir>/<rel1>/<rel2>
			<tree-dir>/<rel1>/<rel2>/<rel3>
			...
			<tree-dir>/<rel-path>

                sort -u

		These are directories not in tree that are needed to
		install new and renamed files.  If any of them exist
		as non-directories, that causes a conflict.

,,install-files-hard-conflicts
		For each line in ,,renamed-files-plan-cooked and
		,,needed-new-files-cooked, the line:

			<tree-dir>/<rel-path>/<tail>

,,renamed-files-mod-old-tree
		<mod-name><space><tree-name>
		sort -k 1

		Files being renamed.  <tree-name> is their old name
		in the tree.

,,renamed-files-plan-plated
		<tree-dir><space>./<rel-path><space><tail><space><old-tree-name>
		    1		       2	       3		4
		sort -k 2

		Files that used to be <old-tree-name> in tree, then
		<old-tree-name> in $tmpdir/renamed-files, should wind
		up as:
			<tree-dir>/<rel-path>/<tail>

,,renamed-files-script
		mv "$tmpdir/renamed-files/<old-tree-name>" \
		   "$tree/<tree-dir>/<rel-path>/<tail>"

		sorted by <rel-path>

		One line for each in ,,renamed-files-plan-plated


,,tree-file-renames
,,tree-dir-renames
	<old-tree-name><space><new-tree-name>
	sort -r -k 1

	For files and dirs renamed (directly) by the patch, the
	old and new names.


,,tree-dir-renames-sed-script
	s:<old-tree-name>\([/<tab]\):<new-tree-name>\1:
	t

	for each line in ,,tree-dir-renames


,,rearranged-tree-dir-index
	<new-tree-name><tab><tag>
	sort -k 2

	The ,,tree-dir-index, taking into account directories
	removed and directories renamed.

	index of dirs not removed | dir-rename script


,,rearrangements-summary
	r<space><old-tree-name><space><new-tree-name>
	d<space><old-tree-name>
	sort -r -k 2

	a list of renamed files and directories and 
	removed directories (but not files)

,,rearrangements_summary_sed_script
	For each "r " line of ,,rearrangements_summary:

	  s:<old-tree-name>\([/<tab]\):<new-tree-name>\1:
	  t

	For each "d " line:

 	  :<old-tree-dir-name>:d

	Note that sorting gives deepest->shallowest for nested
	dirs/files.



,,rearranged-tree-file-index
		<tree-name><tab><tag>
		sort -k 2

		inventory of tree after renaming directories,
		renaming files, removing directories, and removing
		files

,,all-patches
		<rel-path>
		sort

		all regular files under "$delta/patches"

,,patch-list
		<mod-name>
		sort

		List of patch files in delta, under mod names
		of files patched.  For each such file,
		the delta contains patches/<mod-name>.patch

,,patch-map
		<tree-name><space><mod-name>
		sort -k 1

		For every line, <tree-name> is a file in the
		rearranged tree and $delta/<mod-name>.patch a 
		patch file for that file.


,,link-patch-list
		<mod-name>
		sort

		List of link-patch files in delta, under mod names
		of links patched.  For each such file,
		the delta contains patches/<mod-name>.link-mod

,,link-patch-map
		<tree-name><space><mod-name>
		sort -k 1

		For every line, <tree-name> is a file in the
		rearranged tree and $delta/<mod-name>.link-mod a 
		link-patch file for that file.

,,binary-patch-list
		<mod-name>
		sort

		List of binary-patch files in delta, under mod names
		of files patched.  For each such file,
		the delta contains patches/<mod-name>.modified

,,binary-patch-map
		<tree-name><space><mod-name>
		sort -k 1

		For every line, <tree-name> is a file in the
		rearranged tree and $delta/<mod-name>.modified a 
		binary-patch file for that file.


,,metadata-patch-list
		<mod-name>
		sort

,,metadata-patch-map
		<tree-name><space><mod-name>
		sort -k 1

,,dir-metadata-patch-list
		<mod-name>
		sort

,,dir-metadata-patch-map
		<tree-name><space><mod-name>
		sort -k 1


,,missing-file-patch-list


,,final-tree-file-index
,,final-tree-dir-index
		<tree-name><tab><tag>
		sort -k 2

		indexes of the tree after all additions, removals, and
		renames



Here is what `dopatch' does in detail:

\1. Store files removed by the patch in $tmpdir/,,lost-files.tar/
under their old tree names.  (`$tmpdir' is a directory created by
`dopatch' but (normally) removed before `dopatch' exits.)

\2. Remove all files removed by patch./

\3. Copy renamed files to $tmpdir/renamed-files/ under old tree
names.

\4. Remove renamed files from tree./

\5. Move all shuffled dirs to $tmpdir/shuffled-dirs./ A "shuffled
directory" is a directory that is either removed or renamed by the
patch.  When a shuffled directory is moved, all of its contents move
along with it.  Nested directories are moved before their parents.  In
`shuffled-dirs', directories are named by ``ascension number'' (0, 1,
2, etc.).

\6. Rename hard conflicts to renamed dirs./ Any file or directory in
the tree at a location where a renamed directory must be installed is
renamed to ".rej" and the location rembemered in the
`deferred-conflicts' list.

\7. Rename soft conflicts to renamed and new dirs./ Any regular file
that would interfere with creating (`mkdir -p') a newly added
directory or a parent of a renamed directory is renamed with a `.rej'
suffix and the location remembered in the `deferred-conflicts' list.

\8. Install new and renamed dirs./ New directories are created by
`mkdir -p'.  Renamed directories are re-installed with `mkdir -p' for
the parent, then `mv' to put the directory in place.  Nested
directories are created and installed from shallowest to deepest.

\9. Archive removed directories./ Directories removed by patch are
moved to the `++files-removed' tree.  Each directory is moved there
with `mkdir -p' for the parent, then `mv'.  Nested dirs are archived
from shallowest to deepest.

\10. Archive removed files./ The tar file created in step 1 is
unpacked into the `++files-removed' tree.

\11. Rename hard conflicts to new and renamed files./ Any file that
occupies the location needed for a new or renamed file is renamed with
a `.rej' suffix and the location remembered in the
`deferred-conflicts' list.

\12. Rename soft conflicts to new and renamed files, create parent
dirs./ Any regular file in the location of a parent directory for a
new or renamed file is renamed with a `.rej' suffix and the location
remembered in the `deferred-conflicts' list.

\13. Create directories for new and renamed files./ Every directory
needed for new and renamed files is created with `mkdir -p'.

\14. Install renamed files./ Renamed files are re-installed using
`mv'.

\15. Install new files./ New files are copied from the patch to the
tree using `cp -p'.


\16. Patch regular files./

\17. Patch symbolic links./

\18. Patch binary files/

For every `.patch', `.mod-link', or `.modified' file in the delta, if
the corresponding file exists in the tree, try to patch the
corresponding file, winding up with either a cleanly patched file, or
a `.orig' and `.rej' file -- perhaps with a partially patched file.
The partially patched file won't be there if the file in the tree is a
file of the wrong type (e.g., a regular file patch applied to a
symbolic link). Symbolic links and binary files never leave a
partially patched file.

\19. Build a tree of patches for missing files./ Copy the patch files
for all missing files to the file:

	tree/==missing-file-patches--PATCH--DATE

where `PATCH' is the basename of the patch directory, and `DATE' a
timestamp.


\Report Errors/ Finally, `dopatch' prints a summary of errors
encountered.

In any event, after an inexact patch, if the patch went smoothly -- no
(new) `.rej' files will exist.  If the patch encountered problems,
there will be exactly one `.rej' and one `.orig' file for each problem
encountered with a file that exists in tree, and patches in the
`==missing-file-patches' tree for missing files that the patch wanted
to modify.  Use commands such as `find . -name "*.rej"' to locate the
problems.  In the case of complex failures, it may be helpful to study
the patch set itself.

 */
/************************************************************************
 *(h1 "Mapping Names")
 * 

When `dopatch' does its work, there are three sets of files to
consider: the `original' files, the `modified' files, and the `tree'
files.

The `original' and `modified' files are the files seen by `mkpatch'
when the patch was prepared.  Each file has both a location (a path
relative to the root of the tree) and an inventory tag.

The `tree' files are initially the files in the tree being patched.
Again, each has a location and inventory tag.  As the patch proceeds,
the set of `tree' files and the locations of tree files may change
(because of renaming, adding and removing files or directories).

When deciding where new or renamed files and directories are supposed
to be located, `dopatch' uses inventory tags.  For example, suppose
that a new file appeared in the `modified' file list with the
location:

	./a/b/c/new-file

and that in the modified tree, those directories and that file have
the tags:

	./a			tag-a
	./a/b			tag-b
	./a/b/c			tag-c
	./a/b/c/new-file	tag-new-file

Additionally suppose that the `tree' initially contains the directory
(with tag):

	./x/y/z			tag-b

but that the `tree' has no directories with `tag-a' or `tag-c', and no
file with the tag `tag-new-file'.  Where will `dopatch' install
`new-file'?:

	./x/y/z/c/new-file	tag-new-file

`dopatch' chooses that location since `./x/y/z' in the tree being
patched has the same tag as `./a/b' in the modified tree seen by
`mkpatch'.  The new file is supposed to go in the `c' subdirectory of
whatever directory has that tag.

Similarly, supposing that the original tree had a removed file:

	./l/m/n/removed-file	tag-removed-file

and the tree being patched has:

	./x/y/z/removed-file	tag-removed-file

then `dopatch' will remove `./x/y/z/removed-file' from the tree being
patched (since it has the inventory tag of a removed file).


There is a further subtlety.  Suppose that the directory './a/b/c' was
^not^ new in the modified tree.  The patch will, therefore, not
contain explicit instructions to install that directory and will not
contain explicit instructions to install the tag for that directory.
`dopatch' will make a directory named `./x/y/z/c', because it is
needed to install `new-file', but it won't tag that new directory.
The command `arch tree-lint' can be helpful in detecting (hopefully
quite rare) situations like this.

(In ordinary use, either the patch adding `new-file' would in fact
explicitly add directory `c', or you wouldn't apply the patch without
first applying some other patch that explicitly adds `c'.  The problem
only occurs if you are applying patches out-of-order -- in which case
you should expect to have to do some clean-ups by hand.)


1. Store files removed by patch in $tmpdir/,,lost-files.tar
   under their old tree names.

2. Remove all files removed by patch.

3. Copy renamed files to $tmpdir/renamed-files under old tree names.

4. Remove renamed files from tree.

5. Move all shuffled dirs to $tmpdir/shuffled-dirs.

   Nested directories are moved before their parents.
   Directories are renamed to "0", "1", "2", etc.

6. Rename hard conflicts to renamed dirs.

   Any file or directory in the tree at a location where a renamed
   directory must be installed is renamed to ".rej" and the location
   rembemered in the ",,deferred-conflicts" list.

7. Rename soft conflicts to renamed and new dirs.

   Any regular file that would interfere with creating ("mkdir -p")
   a new dir or a parent of a renamed dir is renamed to ".rej"
   and the location remembered in the ",,deferred-conflicts" list.

8. Install new and renamed dirs.

   New directories are created by "mkdir -p".  Renamed directories are
   re-installed with "mkdir -p" for the parent, then "mv".

   Nested directories are created and installed from shallowest to
   deepest.

9. Archive removed directories.

   Directories removed by patch are moved to the ++files-removed...
   directory of the tree.  Each directory is moved there with 
   "mkdir -p" for the parent, then "mv".  Nested dirs are archived
   from shallowest to deepest.

10. Archive removed files.

   The tar file created in step 1 is unpacked into ++files-removed....

11. Rename hard conflicts to new and renamed files.

   Any file that occupies the location needed for a new or renamed
   file is renamed to ".rej" and the location remembered in the
   ,,deferred-conflicts list.

12. Rename soft conflicts to new and renamed files, create parent dirs.

   Any regular file in the location of a parent directory for a new or
   renamed file is renamed to ".rej" and the location remembered
   in the ,,deferred-conflicts list.

13. Create directories for new and renamed files.

   Every directory needed for new and renamed files is created with
   "mkdir -p".

14. Install renamed files.

   Renamed files are re-installed using "mv".

15. Install new files.

   New files are copied from the patch to the tree using "cp -p".


16. Patch regular files that are present in the tree.

   For every ".patch" file in the patch set, if the corresponding file
   exists in the tree, try to patch that file.

   If the file is a symbolic link, the file is renamed to ".orig" 
   and the entire ".patch" file copied to a ".rej" file.

   If that patch applies cleanly, only the modified file is left.  If
   the patch fails to apply cleanly, a partially patched file is left,
   along with a ".orig" file (an unmodified copy of the file as it was
   before trying to apply the patch) and a ".rej" file (containing
   context diffs that could not be applied to the file).


17. Patch symbolic links that are present in the tree.

    For every ".link-mod" file in the patch set, if the corresponding
    file exists in the tree, try to patch that file.

    Here is a decision tree that describes how symbolic link patches
    are applied:

	* Patch set contains a ".link-orig" file

	  In this case, the patch expects to find a symbolic link
	  in the tree, matching the target recorded in ".link-orig".
	  Such a link should be retargetted to the target recorded in
	  the ".link-mod" file.  There are three possible outcomes:

	** the file in the tree is not a symbolic link

	** the file in the tree is a symbolic link, but the link
	   target does not match the the patch set ".link-orig" file

	  In both of these cases, the file in the tree is renamed with
	  a ".orig" suffix.  A ".rej" file is created -- a symbolic
	  link with the target specified in the ".link-mod" file.  The
	  metadata for the ".rej" file is initialized to be the same
	  as the metadata of the ".orig" file.  Additionally, a link
	  is created with a ".patch-orig" suffix -- that link
	  targetted to the file specified in the ".link-orig" file of
	  the patch set.  If the patch set contains a ".meta-orig"
	  file for the link, the ".patch-orig" link is set to have
	  that metadata; otherwise the user's defaults are used.

	** the file in the tree is a symbolic link matching the
	  ".link-orig" file

	  In this case, the link is replaced by a link to the target
	  specified in ".link-mod" and the metadata for the new link
	  copied from the link originally in the tree.


	* Patch set contains a ".original" file

	  In this case, the patch expects to find a regular file in
	  the tree whose contents are the same as the ".original"
	  file.  The patch wants to replace that file with a symbolic
	  link.

	** cmp reports that the tree file and ".original" file match

	  In this case, the tree file is deleted and replaced by a
	  symbolic link whose metadata is copied from the just-deleted
	  file.  Note that "cmp" doesn't care whether the tree file
	  was a regular file or a symbolic link to a regular file.

	** cmp reports that the tree file and ".original" file do not
           match.

	  The tree file is renamed with a ".orig" suffix.  The desired
	  link is created with a ".rej" suffix and metadata copied
	  from the ".orig" suffix.  The ".original" file from the
	  patch set is copied to the tree with a ".patch-orig" suffix,
	  preserving metadata.


18. Patch binary files

   If the patch set contains a ".modified" file, it wants to replace 
   a file in the tree with a complete copy of that ".modified" file.
   Here is a decision tree:

	* patch set contains a ".link-orig" file

	  The patch wants to replace a symbolic link by a copy of
	  the ".modified" file.

	** tree has a non-matching link
	** tree has a regular file

	  In both cases, the file in the tree is renamed with a
	  ".orig" suffix and the new link created with a ".rej" suffix
	  and metadata copied from the ".orig" file.  The old link
	  (specified in the patch set ".link-orig" file) is created
	  with a ".patch-orig" suffix and metadata from either the
	  patch set ".meta-orig" file (if it exists) or the user's
	  defaults.

	** tree has a matching link

	  The link is replaced by the ".modified" file (without any
	  suffix) with metadata copied from the file being
	  replaced.

	* patch set contains a ".original" file

	  The patch wants to replace a file with the same contents as
	  ".original" with a copy of ".modified".  If `cmp' reports
	  a match, the `.modified' file is installed (sans suffix)
	  with metadata copied from from the file it replaces.

	  If the files don't match, the tree file is renamed to
	  ".orig".  The ".modified" file copied to ".rej", with
	  metadata copied from the ".orig" file.  The ".original" file
	  is copied to a ".patch-orig" file, preserving metadata.

19. Patch File Metadata

   For every ".meta-mod" file in the delta, if the corresponding file
   exists in the tree, patch its metadata.  If the file doesn't exist, 
   but a ".rej" file does, and the ".rej" file is not from a regular
   ".patch" (i.e., the ".rej" file is either a symbolic link or a
   complete copy of a binary file), then patch the metadata for the
   ".rej" file.

   Metadata is patched by comparing the metadata of the file being
   patched to the metadata recorded in the ".meta-org" file in the
   patch set.  If they are the same, the metadata (currently only file
   permissions) are changed to be the same as those recorded in the
   ".meta-mod" file.

   After those steps, if the file's metadata does not match the data
   in ".meta-mod", copy the ".meta-mod" file to the tree as a
   ".meta.rej" file.

20. Patch Directory Metadata

   For every "=dir-meta-mod" file in the patch set, if the
   corresponding directory in the tree has the same metadata as
   recorded in the "=dir-meta-orig" file, apply the settings from the
   "=dir-meta-mod" file (currently only file permissions).

   After that, if the file's metadata does not match the settings in
   "=dir-meta-mod" the copy that patch file to the tree as
   "=dir-meta.rej".

21. Build a tree of patches for missing files and wrong-typed files

   Three kinds of patches weren't applied at all in the previous
   steps:

	* patches for files, links, or directories missing from the
          tree

	* patches for directories but the tree has a link or regular
          file

	* patches for links or regular files, but the tree has a
          directory 

   All the patch files for those cases are copied to a subdirectory
   installed at the root of the tree being patched, having a name of
   the form:

	==missing-file-patches-PATCHNAME-DATE

   where `PATCHNAME' is the basename of the patch set directory and
   `DATE' a timestamp.






add .meta, .meta.rej to non-source (backup) files
    .patch-orig


# tag: Tom Lord Mon Dec 10 01:32:37 2001 (patch-sets/DOPATCH)
#
