SMERGE(1)

NAME
smerge - compare SCCS hierarchies

SYNOPSIS
smerge [ -f smergefile ] [ -l listfile | -L listfile ] [ -bdeIiknqs ] [ macro_def ... ] [ files ... ]

DESCRIPTION

smerge compares pairs of SCCS files and executes commands in smergefile based on the status of the files. Smergefile may contain a series of commands for each possible state of a pair of SCCS files. If no -f option is present, smerge uses smergefile. If smergefile is not present, then Smergefile is used.

Large portions of the make command have been used in smerge in order to provide a form of macro processing and command execution that the user is most likely to be familiar with.

macro_def is a quoted string containing a macro definition. This definition overrides any definition for the specified macro that occurs in the smergefile itself. See Macros, below, for details.

Files is a list of SCCS file names. Alternatively, file names can be read from a file specifiled by the -l option or generated automatically and written to a file specified by the -L option.

OPTIONS

-f smergefile
    Use the command file smergefile. More than one -f smergefile argument is considered an error.

-l listfile | -L listfile
    Listfile is a list of names to be used in SCCS file name generation. Leading white space, empty lines and lines beginning with '#' are ignored. If listfile is - then input is taken from the standard input. If the -L option is used, smerge will generate the list of files itself and write it to listfile.

    WARNING: the -L option uses the find(1) command to generate the list of names. Find will not follow symbolic links in the SCCS hierarchy.

-b  Do not ignore branch deltas when calculating the base and top revision numbers. Branch deltas are always listed in the macros newsid1 and newsid2 if they are included by the top delta in a SCCS file.

-d  Debug mode.

-e  Environment variables override assignments within smergefiles.

-I  Do not stop processing after SCCS file format errors are encountered.

-i  Ignore error codes returned by invoked commands.

-k  If an invoked command returns an error code, stop processing commands for the current SCCS file pair and continue with the next pair. This option is disabled by the -i option.

-n  No execute mode. Print commands, but do not execute them. Even lines beginning with an @ are printed.

-q  "Quick". Two shortcuts are taken:

    1) If one file exists but the other doesn't, then the state of the existent file is old and the state of the non-existent file is none. The SCCS file is not read and the top and base macros are not set.

    2) If both files exist and they have identical SCCS headers, then the state of both is set to old. The top and base macros are not set.

-s  Silent mode. Do not print command lines before executing.

SCCS FILE NAME GENERATION
The important effects of the way smerge generates file names are:

1)  Symbolic links in path names followed by ".." behave the same as directories followed by "..".

2)  No matter what format the input file name is in, the name that smerge uses will have the form: directory/SCCS/s.file.

For every filename that smerge processes, two SCCS file names are generated. The first name is constructed from the value of the environment variable tree1, followed by the directory part of the file name, followed by "SCCS/s.", followed by the file part of the file name. Extraneous "./", "//", "SCCS/s.", and dir"/.." are removed during file name generation. The second SCCS file name is similarly generated using the value of the environment variable tree2.

If either tree1 or tree2 cannot be found in the environment, smerge prints an error message and stops processing.

SCCS FILE COMPARISON
For each of the two SCCS files, a check sum and byte count is generated for every SCCS revision in the SCCS file. The list of check sums and byte counts are then compared to determine the newest matching delta (base delta), and the the most recent delta (top delta). The state for each file can be none, old, new, ambiguous, nobase, or sccserror.

The possible resulting state pairs are analagous to make's targets:

none.none
    Neither file exists.

old.none
    The first SCCS file exists, the second does not.

none.old
    The first SCCS file does not exist, the second does.

old.old
    The base deltas are identical to the top deltas. As far as smerge is concerned, nothing has changed.

new.old
    The top delta of the first file is different than its base delta. The top delta of the second file is the same as its base delta.

old.new
    The top delta of the first file is the same as its base delta. The top delta of the second file is different from its base delta.

new.new
    Both files' base deltas are different from their respective top deltas.

nobase
    There is no common revision. Note that "nobase.nobase" is not used by smerge.

ambiguous
    This happens most often when a recent delta is backed out by laying an older delta on top of it. In the diagram below, identical SCCS deltas are connected by lines. The top delta for file1 is 1.7, the top delta for file2 is 1.5.

		file1   file2
		1.7
		1.6
		1.5     1.5--+
		1.4-----1.4  |
		1.3-----1.3--+

    From the point of view of file1, the base deltas are 1.4 for file1 and 1.4 for file2. From the point of view of file2 the base deltas are 1.3 for file1 and 1.5 for file2.

    Smerge calculates both views and uses the other file's conception of the base delta.

    As a result, if the state of a file pair is ambiguous, the base deltas reported by smerge will not contain the same data. The list of new deltas for a file (newsid1 or newsid2) will contain everything that is new for that file relative to the other file.

    Note that "ambiguous.ambiguous" is not used by smerge.

sccserror
    There is a format error in one or both of the SCCS files. Smerge will exit after executing the commands for this target unless the -I flag is specified on the command line.

default
    If no smergefile is given or found, or no commands are given for a particular state, the commands given for default are executed. If no commands are given for default then the command "echo $(state1).$(state2) $(dir)/$(file)" is simulated.

USAGE

  Smergefile Target Entries

An important difference between make and smerge is the way targets are executed. Make will execute the first target found in a makefile unless a specific target is specified on the command line. Smerge behaves as if it were executed once for every pair of SCCS files that it given using a state name pair, described in SCCS File Comparison above, as the name of the target to be executed.

Make recursively executes each dependency target that is out of date with respect to the dependent target. The preamble targets in smerge act as subroutines. Smerge has no concept of "out-of-date" targets and always executes the preamble targets before executing the primary target.

Other than include lines, comments and macro definitions which are described below, a smergefile contains a sequence of entries that specify targets. A target entry has the following format:

    target-name:  preamble-target ...
    	command
    	...

The first line contains the name of a target terminated with a colon (:). This is followed by a (possibly empty) list of preamble targets terminated by a new-line. Subsequent lines in the entry begin with a TAB, or SPACE and contain Bourne shell commands. These commands are performed for every SCCS file pair where the string "$(state1).$(state2)" matches the target name.

Shell commands may be continued across input lines by escaping the newline with a backslash (\). The continuation line must also start with a TAB. smerge expands any macros and passes each command line (except the initial TAB) directly to a Bourne shell. Note that smerge does not remove escaped newlines from shell lines as does make. Thus,
    echo a\
    echo b

produces the shell commands
    echo a echo b
instead of
    echo aecho b
as the shell does.

The first line that does not begin with a TAB or # begins another target or a macro definition.

  Special Characters

#   Start a comment. The comment ends at the next newline.

$   Macro expansion. See Macros, below, for details.

-   Following the tab, if the first character of a command line is a -, smerge ignores a nonzero return status when executing that command. smerge normally terminates when a command returns nonzero status.

@   Following the tab, if the first character is a @, smerge does not print the command line before executing it (C-Shell users note that there is no @ built-in command for the Bourne shell).

    If - and @ appear as the first two characters after the TAB, both apply.

$$var
    Escape macro expansion. Pass $var on to the shell (for variable substitution).

  Executing Command Lines

Command lines are executed one at a time, each by its own shell. A line is printed (after macro expansion) as it executed unless it starts with a @, or smerge is run with the -s option. Although the -n option specifies printing without execution, lines containing the string $(MAKE) are executed regardless.

To take advantage of the Bourne shell if control statement, use a command line of the form:

    ...
    if expression ; \
    then command ; \
    command ; \
    ...
    else command ; \
    ...
    fi

Although composed of several input lines, the escaped newlines insure that smerge treats them all as one command line.

To take advantage of the Bourne shell for control statement, use a command line of the form:

    ...
    for var in list ; do \
    command ; \
    ...
    done

To write shell variables, use double dollar-signs ($$) to escape macro expansion of the dollar sign by smerge.

  Include Files

smerge has an include file capability. If the string include appears as the first seven letters of a line in a smergefile and is followed by a space or a tab, the string following the word include is taken as a filename which the current invocation of smerge will read. include files can be nested to a depth of no more than about 16.

  Macros
Entries of the form

    string1 = string2

are macro definitions. string2 is defined as all characters up to a comment character or an unescaped newline. Subsequent appearances of

    $(string1)

are replaced by string2. The parentheses are optional if a single character macro name is used.

Substitutions within macros can be made as follows:

    $(string1:subst1=subst2)

When the substitution sequence :subst1=subst2 is specified, all non-overlapping occurrences of subst1 in the named macro are replaced by subst2. Strings (for the purposes of this type of substitution) are delimited by blanks, tabs, newline characters, and the beginning of a line.

  Internal Macros
Smerge defines several macros for each SCCS file pair. tree1 and tree2 must be defined somewhere by the user (environment variables, on the command line, or in smergefile.) dir and file are set during SCCS file name generation and are the directory and file parts of the file name. base1 and base2 specify the newest common SCCS revisions. If the state is nobase then both base1 and base2 are set to the null string. If the state is ambiguous then base1 and base2 do not represent identical data. Branch deltas are not considered in the comparisons unless the -b option is specified. top1 and top2 are the newest delta for each file that is not a branch delta. The -b option allows top1 and top2 to be branch deltas. The newsid macros, newsid1 and newsid2, include a list of all the SCCS revisions numbers from a file's base to its top. This list contains all included deltas, and branch deltas, and does not contain excluded or ignored deltas. state1 and state2 represent the state of each file. The possible values are none, new, old, ambiguous, nobase, or sccserror.

ENVIRONMENT
smerge reads the environment. Environment variables are assumed to be macro definitions and are processed as such. Environment variables are processed before any smergefile ; thus, macro assignments in a smergefile override environment variables (for that smergefile only). The -e option makes the environment override the macro assignments in a smergefile.

EXAMPLES
#
# This smergefile is used to take new deltas from one SCCS hierarchy
# and add then to the SCCS files in another SCCS hierarchy.
# It is only an example.
#
# tree1 will receive all the updates
tree1=/usr/src/SCCS_DIRECTORIES
# tree2 contains recent development
tree2=/mystuff/usr/src/SCCS_DIRECTORIES
#
# This is the hard case; both heirarchies have changed and someone
# is going to have to manually inspect and merge the files.
# Do some diffs and get the SCCS history for each version.
# The last line is separate because the exit code from diff is the
# only one to ignore.
#
merge:
	@cd $(tree1)/$(dir);	\
	rm -f $(file).prs1 $(file).prs2 SCCS/s.$(file);	\
	for sid in $(newsid1); do	\
	 sccs prs -r$$sid $(tree1)/$(dir)/SCCS/s.$(file) >> $(file).prs1; \
	done;	\
	for sid in $(newsid2); do	\
	 sccs prs -r$$sid $(tree2)/$(dir)/SCCS/s.$(file) >> $(file).prs2; \
	done;	\
	sccs get -p -k $(tree1)/$(dir)/SCCS/s.$(file) > $(file).OFC; \
	sccs get -p -k $(tree2)/$(dir)/SCCS/s.$(file) > $(file).MINE;
	-cd $(tree1)/$(dir); diff $(file).OFC $(file).MINE > $(file).DIFF;
#
# These are various "subroutine" targets
#
head:
	@echo '$(dir)/$(file) tops($(top1),$(top2)) bases($(base1),$(base2))';\
	echo newsid1 = $(newsid1);\
	echo newsid2 = $(newsid2);
newhead:
	@echo -n "NORMAL		"
ahead:
	@echo -n "AMBIGUOUS	"
nbhead:
	@echo -n "NOBASE		"
nfhead: head
	@echo -n "NEWFILE	"
#
# All the hard cases
#
new.new: newhead head merge
ambiguous: ahead head merge
nobase: nbhead head merge
# no change
old.old:
new.old: old.old
# The file does not exist in tree1
none.old: nfhead
	cp $(tree2)/$(dir)/SCCS/s.$(file) $(tree1)/$(dir)/SCCS/s.$(file);\

#
# Add each of the new revisions to the official SCCS file.
# Maintain the original delta commentary.
#
old.new:
	set -k;	\
	cd $(tree1)/$(dir);	\
	for sid in $(newsid2);	\
	do	\
		sccs edit $(file);	\
		sccs get -pk -r$$sid $(tree2)/$(dir)/SCCS/s.$(file) > $(file);\
		sccs prs -r$$sid $(tree2)/$(dir)/SCCS/s.$(file) |\
			awk '	\
				NR == 1 { tag = $$0 "\\"; incomments = 0; } \
				/^COMMENTS:/ { \
						incomments = 1; \
						print "Original tag: " tag ;\
						next; \
					} \
				incomments == 1 { print $$0 "\\"; } \
				END { print }	\
			' - | \
			sccs delta $(file); \
	done
none.none:
	@echo Bogus file name $(dir)/$(file)
#
# Smerge has already printed a message giving the SCCS file name and the
# type of corruption before executing the sccserror target.
#
sccserror:
	@if [ $(state1) = "sccserror" ]; \
	then \
		echo WARNING $(tree1)/$(dir)/$(file) IS CORRUPT; \
	fi; \
	if [ $(state2) = "sccserror" ]; \
	then \
		echo WARNING $(tree1)/$(dir)/$(file) IS CORRUPT; \
	fi

To run the above smergefile from the Borne shell:

$ tree1=/usr/src/SCCS_DIRECTORIES
$ tree2=$HOME/mystuff/usr/src/SCCS_DIRECTORIES
$ export tree1 tree2
$ # generate a list of file names
$ ( cd $tree1 ; find . -name 's.*' -print ;
> cd $tree1 ; find . -name 's.*' -print ) | sort -u > filenames
$ smerge -l filenames

To find out the status of all SCCS files use the file name list generated in the above example and run the following command:

$ smerge -f /dev/null -l filenames

The use of /dev/null in the above command is not manditory. It guards against using any Smergefile or smergefile that you may have in the current directory.

FILES
[Ss]mergefile

SEE ALSO
ssum(1), sccsreorg(1), make(1), sh(1), sccs(1), diff(1), sum(1), getopt(3), sccsname(1)

BUGS
Some commands return nonzero status inappropriately; use -i to overcome the difficulty. File names with the characters = : @ will not work.

Commands that are directly executed by the shell, notably cd, are ineffectual across new-lines in smerge.

Smerge treats an open error on an existing file as if the file did not exist.

WARNINGS
smerge uses the checksum routine from sum(1) and a byte count for each delta in order to determine matching SCCS deltas. There is a small probability that the same checksum and byte count can be generated for different deltas.

The -L option uses the find(1) command to generate the list of names. Find will not follow symbolic links in the SCCS hierarchy.

The example Smergefile in this document will not work for you.