v14i070: Unified context diff tools
Wayne Davison
davison at dri.com
Fri Aug 31 10:18:07 AEST 1990
Posting-number: Volume 14, Issue 70
Submitted-by: davison at dri.com (Wayne Davison)
Archive-name: unidiff/part01
[A brief excerpt from the PROPAGANDA file:]
I've created a new context diff format that combines the old and new hunks into
one unified hunk. The result? The unified context diff, or "unidiff."
Posting your patch using a unidiff will usually cut its size down by around
25% (I've seen from 12% to 48%, depending on how many redundant context lines
are removed). Even if the diffs are generated with only 2 lines of context,
the savings still average around 20%.
Keep in mind that *no information is lost* by the conversion process. Only
the redundancy of having multiple identical context lines. [...]
I've included:
o a patch to make gnudiff (v1.14) generate a unidiff.
o a patch to make patch (patchlevel 12) accept a unidiff.
o a versatile program called "unify" that can translate from a context
diff (new- or old-style) into a unidiff, and from a unidiff into a
true new-style context diff.
o a man page for unify.
o a 1.3k bandaid called "unipatch" that translates a unidiff into a
context diff format that older versions of patch can understand.
(It outputs a slightly degenerate form of a context diff (no '!'s)
but it works great with patch.)
o a Makefile to get you going quickly.
--
\ /| / /|\/ /| /(_) Wayne Davison
(_)/ |/ /\|/ / |/ \ davison at dri.com
(W A Y N e) ...!uunet!drivax!davison
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
# PROPAGANDA
# README
# Makefile
# unify.c
# unify.1
# unipatch.c
# gnudiff.uni
# patch.uni
# This archive created: Mon Aug 20 22:23:52 1990
# By: Wayne Davison (Digital Research, Monterey CA)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'PROPAGANDA'" '(1966 characters)'
if test -f 'PROPAGANDA'
then
echo shar: "will not over-write existing file 'PROPAGANDA'"
else
sed 's/^X//' << \SHAR_EOF > 'PROPAGANDA'
XI've created a new context diff format that combines the old and new hunks into
Xone unified hunk. The result? The unified context diff, or "unidiff."
X
XPosting your patch using a unidiff will usually cut its size down by around
X25% (I've seen from 12% to 48%, depending on how many redundant context lines
Xare removed). Even if the diffs are generated with only 2 lines of context,
Xthe savings still average around 20%.
X
XKeep in mind that *no information is lost* by the conversion process. Only
Xthe redundancy of having multiple identical context lines.
X
XIf you're worried that some people will be unable to apply a patch released
Xin unidiff format then you could include the "unipatch.c" program -- 1.3k of C
Xsource that converts a unidiff into a context diff that any version of patch
Xcan understand. If your patch is at least 10k, you'll STILL be saving space.
X
XNot worth the hassle? I disagree. The goal of saving net bandwidth (not to
Xmention storage space) is a good one. The conversion process will take some
Xtime, but I've attempted to make it as painless as possible. I've included:
X
X o a patch to make gnudiff (v1.14) generate a unidiff.
X o a patch to make patch (patchlevel 12) accept a unidiff.
X o a versatile program called "unify" that can translate from a context
X diff (new- or old-style) into a unidiff, and from a unidiff into a
X true new-style context diff.
X o a man page for unify.
X o a 1.3k bandaid called "unipatch" that translates a unidiff into a
X context diff format that older versions of patch can understand.
X (It outputs a slightly degenerate form of a context diff (no '!'s)
X but it works great with patch.)
X o a Makefile to get you going quickly.
X
XUse this package to "unify" your site, and then save it to help others. Mail
Xthe 1.3k bandaid to anyone who complains about being unable to apply a unidiff,
Xand also offer to supply the whole conversion package if desired. Soon, the
Xwhole net will be unified. ;-)
SHAR_EOF
fi
echo shar: "extracting 'README'" '(1811 characters)'
if test -f 'README'
then
echo shar: "will not over-write existing file 'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
XThe two patches included in this package are in unidiff format, but they are
Xvery easy to apply with the included utilities.
X
XThe easiest way to get going is to give the included Makefile the once-over
Xand then type:
X
X make
X
Xand you'll get a runnable version of unify which is used to translate the
Xunidiffs into their context diff counterparts (patch.uni into patch.diff,
Xand gnudiff.uni into gnudiff.diff). It's all done automatically for you.
X
XThe other alternative is to:
X
X make unipatch
X
Xand patch the source to patch with:
X
X unipatch <patch.uni | patch
X
Xand then apply the gnudiff.uni patch using the same method or the new version
Xof patch.
X
XThe file patch.diff expects to find patchlevel 12 of patch, changing the
Xpachlevel to 12u. The only added option is -u, which forces a patch to
Xbe interpreted as a unidiff.
X
XThe file gnudiff.diff expects to find version 1.14 of gnudiff, changing the
Xversion to 1.14u. The patch adds the following options:
X
X -u generates a unidiff.
X -P turns on patch-output mode:
X o Outputs an "Index: filename" line instead of the ***/--- header
X lines (even for normal and context diffs). The filename chosen
X is the shorter of the two we're diff'ing, and the characters "./"
X are skipped if present at the start of the name.
X o Doesn't print "Only in <dir>", "Common subdirectories", or
X "diff <-opts> <file1> <file2>" messages.
X o Turns on the '=' prefix in a unidiff instead of the (more
X readable) ' ' for lines that are in common.
X -U same as -uP.
X
X +unidiff equivilent to 'u'
X +patch equivilent to 'P'
X
XSwitches for the unify program are very similar to those for diff, and are
Xspecified in the man page.
X
X \ /| / /|\/ /| /(_) Wayne Davison
X(_)/ |/ /\|/ / |/ \ davison at dri.com
X (W A Y N e) ...!uunet!drivax!davison
SHAR_EOF
fi
echo shar: "extracting 'Makefile'" '(353 characters)'
if test -f 'Makefile'
then
echo shar: "will not over-write existing file 'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X# A simple makefile for unify, unipatch, and the unidiff patches.
X#
X
XCC= cc
XCFLAGS= -O
X
Xall: patch.diff gnudiff.diff
X
Xpatch.diff: patch.uni unify
X unify patch.uni >patch.diff
X
Xgnudiff.diff: gnudiff.uni unify
X unify gnudiff.uni >gnudiff.diff
X
Xunify: unify.c
X $(CC) $(CFLAGS) -o unify unify.c
X
Xunipatch: unipatch.c
X $(CC) $(CFLAGS) -o unipatch unipatch.c
SHAR_EOF
fi
echo shar: "extracting 'unify.c'" '(10829 characters)'
if test -f 'unify.c'
then
echo shar: "will not over-write existing file 'unify.c'"
else
sed 's/^X//' << \SHAR_EOF > 'unify.c'
X/*
X** unify.c - change a diff to/from a context diff from/to a unidiff.
X**
X** Author: Wayne Davison <davison at dri.com> (uunet!drivax!davison)
X**
X** Feel free to use this code in any way you desire.
X*/
X
X#include <stdio.h>
X
Xextern char *malloc();
X
X#define FIND_NEXT 0
X#define PARSE_UNIDIFF 1
X#define UNI_LINES 2
X#define PARSE_CDIFF 3
X#define PARSE_OLD 4
X#define CHECK_OLD 5
X#define OLD_LINES 6
X#define PARSE_NEW 7
X#define NEW_LINES 8
X
X#define strnEQ(s1,s2,n) (!strncmp(s1,s2,n))
X#define strnNE(s1,s2,n) strncmp(s1,s2,n)
X
Xchar buf[2048];
X
Xstruct liner {
X struct liner *link;
X char type;
X int num;
X char str[1];
X} root, *head = &root, *hold = &root, *line;
X
Xlong o_first = 0, o_last = -1;
Xlong n_first = 0, n_last = 0;
X
Xlong o_start, o_end, o_line;
Xlong n_start, n_end, n_line;
X
Xlong line_num = 0;
Xint input_type = 0;
Xint output_type = 0;
Xint echo_comments = 0;
Xint strip_comments = 0;
Xint patch_format = 0;
X
Xint state = FIND_NEXT;
Xint found_index = 0;
Xchar name[256] = { '\0' };
X
Xvoid ensure_name(), add_line(), generate_output();
X
Xint
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X char type;
X char ndiff; /* Equals '*' when we have a new-style context diff */
X FILE *fp_in = stdin;
X
X while (--argc) {
X if (**++argv == '-') {
X while (*++*argv) {
X switch (**argv) {
X case 'c': /* force context diff output */
X output_type = 2;
X break;
X case 'e': /* echo comments to stderr */
X echo_comments = 1;
X break;
X case 'p': /* generate patch format */
X case 'P':
X patch_format = 1;
X break;
X case 's': /* strip comment lines */
X strip_comments = 1;
X break;
X case 'U': /* force patch-unidiff output */
X patch_format = 1;
X case 'u': /* force unidiff output */
X output_type = 1;
X break;
X default:
X fprintf(stderr, "Unknown option: '%c'\n", **argv);
X exit(1);
X }
X }
X } else {
X if (fp_in != stdin) {
X fprintf(stderr, "Only one filename allowed.\n", *argv);
X exit(1);
X }
X if ((fp_in = fopen(*argv, "r")) == NULL) {
X fprintf(stderr, "Unable to open '%s'.\n", *argv);
X exit(1);
X }
X }
X }
X
X while (fgets(buf, sizeof buf, fp_in)) {
X line_num++;
X reprocess:
X switch (state) {
X case FIND_NEXT:
X if (input_type < 2 && strnEQ(buf, "@@ -", 4)) {
X input_type = 1;
X if (!output_type) {
X output_type = 2;
X }
X ensure_name();
X state = PARSE_UNIDIFF;
X goto reprocess;
X }
X if (!(input_type & 1) && strnEQ(buf, "********", 8)) {
X input_type = 2;
X if (!output_type) {
X output_type = 1;
X }
X ensure_name();
X state = PARSE_OLD;
X break;
X }
X if (strnEQ(buf, "Index: ", 7)) {
X found_index = 1;
X printf("%s", buf);
X } else if (strnEQ(buf, "Prereq: ", 8)) {
X printf("%s", buf);
X } else if (strnEQ(buf, "*** ", 4) || strnEQ(buf, "--- ", 4)) {
X if (!found_index) {
X char *cp;
X int len;
X
X for (cp=buf+4,len=0; *cp>' ' && len<255; cp++,len++) {
X ;
X }
X if (!*name || len < strlen(name)) {
X strncpy(name, buf+4, len);
X name[len] = '\0';
X }
X }
X if (!patch_format) {
X printf("%s", buf);
X }
X } else if( patch_format
X && (strnEQ(buf, "Only in ", 8) || strnEQ(buf, "Common subdir", 13)
X || strnEQ(buf, "diff -", 6))) {
X if (echo_comments) {
X fprintf(stderr, "%s%s", strip_comments ? "" : "!!! ", buf);
X }
X } else {
X if (echo_comments) {
X fprintf(stderr, "%s", buf);
X }
X if (!strip_comments) {
X printf("%s", buf);
X }
X }
X break;
X case PARSE_UNIDIFF:
X if (strnNE(buf, "@@ -", 4)) {
X found_index = 0;
X *name = '\0';
X state = FIND_NEXT;
X goto reprocess;
X }
X if (sscanf(buf+4, "%ld,%ld +%ld,%ld %c",
X &o_start, &o_end, &n_start, &n_end, &type) != 5 || type != '@') {
X fprintf(stderr, "Invalid unidiff header at line %ld.\n",
X line_num);
X exit(1);
X }
X o_end = (o_start ? o_start + o_end - 1 : 0);
X n_end = (n_start ? n_start + n_end - 1 : 0);
X o_first = o_start;
X n_first = n_start;
X if (o_start) {
X o_line = o_start-1;
X } else {
X o_line = o_last = 0;
X }
X if (n_start) {
X n_line = n_start-1;
X } else {
X n_line = n_last = 0;
X }
X state = UNI_LINES;
X break;
X case UNI_LINES:
X switch (*buf) {
X case ' ':
X case '=':
X *buf = ' ';
X o_last = ++o_line;
X n_last = ++n_line;
X break;
X case '-':
X o_last = ++o_line;
X break;
X case '+':
X n_last = ++n_line;
X break;
X default:
X fprintf(stderr, "Malformed unidiff at line %ld.\n",
X line_num);
X exit(1);
X }
X add_line(*buf, 0, buf+1);
X if (o_line == o_end && n_line == n_end) {
X generate_output();
X state = PARSE_UNIDIFF;
X }
X break;
X case PARSE_CDIFF:
X if (strnNE(buf, "********", 8)) {
X generate_output();
X found_index = 0;
X *name = '\0';
X state = FIND_NEXT;
X goto reprocess;
X }
X state = PARSE_OLD;
X break;
X case PARSE_OLD:
X ndiff = ' ';
X o_start = -1;
X if (sscanf(buf, "*** %ld,%ld %c", &o_start, &o_end, &ndiff) < 2) {
X if (o_start < 0) {
X fprintf(stderr,
X "Context diff missing 'old' header at line %ld.\n",
X line_num);
X exit(1);
X }
X o_end = o_start;
X ndiff = ' ';
X }
X if (o_last >= 0) {
X if (o_start > o_last) {
X generate_output();
X } else {
X ndiff = ' ';
X while (head->link && head->link->num != o_start) {
X head = head->link;
X }
X }
X }
X o_line = o_start-1;
X n_line = 0;
X if (!o_first) {
X o_first = o_start;
X }
X if (!o_start) {
X state = PARSE_NEW;
X } else {
X state = CHECK_OLD;
X }
X break;
X case CHECK_OLD:
X if (strnEQ(buf, "--- ", 4)) {
X state = PARSE_NEW;
X } else {
X state = OLD_LINES;
X hold = head;
X }
X goto reprocess;
X case OLD_LINES:
X if (buf[0] == '\n') {
X strcpy(buf, " \n");
X }
X if (buf[1] == '\n') {
X strcpy(buf+1, " \n");
X }
X if (buf[1] != ' ') {
X fprintf(stderr, "Malformed context diff at line %ld.\n",
X line_num);
X exit(1);
X }
X switch (*buf) {
X case ' ':
X type = ' ';
X n_line++;
X o_line++;
X break;
X case '-':
X case '!':
X type = '-';
X o_line++;
X break;
X default:
X fprintf(stderr, "Malformed context diff at line %ld.\n",
X line_num);
X exit(1);
X }
X if (o_line > o_last) {
X add_line(type, 0, buf+2);
X o_last = o_line;
X n_last = n_line;
X } else {
X do {
X hold = hold->link;
X } while (hold->type == '+');
X if (type != ' ') {
X hold->type = type;
X hold->num = 0;
X }
X }
X if (o_line == o_end) {
X state = PARSE_NEW;
X }
X break;
X case PARSE_NEW:
X if (*buf == '\n') {
X break;
X }
X n_start = -1;
X if (sscanf(buf, "--- %ld,%ld", &n_start, &n_end) != 2) {
X if (n_start < 0) {
X fprintf(stderr,
X "Context diff missing 'new' header at line %ld.\n",
X line_num);
X exit(1);
X }
X n_end = n_start;
X }
X n_last = n_line;
X o_line = o_start ? o_start-1 : 0;
X n_line = n_start ? n_start-1 : 0;
X n_last += n_line;
X hold = head;
X if (!n_first) {
X n_first = n_start;
X while (hold->link && hold->link->type == '-') {
X hold = hold->link;
X hold->num = ++o_line;
X }
X }
X if (ndiff == '*' && n_last == n_end) {
X state = PARSE_CDIFF;
X break;
X }
X state = NEW_LINES;
X break;
X case NEW_LINES:
X if (buf[0] == '\n') {
X strcpy(buf, " \n");
X }
X if (buf[1] == '\n') {
X strcpy(buf+1, " \n");
X }
X if (buf[1] != ' ') {
X fprintf(stderr, "Malformed context diff at line %ld.\n",
X line_num);
X exit(1);
X }
X switch (*buf) {
X case ' ':
X type = ' ';
X n_line++;
X o_line++;
X break;
X case '+':
X case '!':
X type = '+';
X n_line++;
X break;
X default:
X fprintf(stderr, "Malformed context diff at line %ld.\n",
X line_num);
X exit(1);
X }
X if (o_line > o_last) {
X o_last = o_line;
X add_line(type, o_line, buf+2);
X n_last++;
X } else if (type != ' ') {
X add_line(type, 0, buf+2);
X n_last++;
X } else {
X hold = hold->link;
X hold->num = o_line;
X while (hold->link && !hold->link->num
X && hold->link->type != ' ') {
X hold = hold->link;
X if (hold->type == '-') {
X hold->num = ++o_line;
X }
X }
X }
X if (o_line == o_end && n_line == n_end) {
X state = PARSE_CDIFF;
X }
X break;
X }/* switch */
X }/* while */
X generate_output();
X
X return 0;
X}
X
Xvoid
Xensure_name()
X{
X char *cp = name;
X
X if (!found_index) {
X if (!*name) {
X fprintf(stderr,
X "Couldn't find a name for the diff at line %ld.\n",
X line_num);
X } else if (patch_format) {
X if (cp[0] == '.' && cp[1] == '/') {
X cp += 2;
X }
X printf("Index: %s\n", cp);
X }
X }
X}
X
Xvoid
Xadd_line(type, num, str)
Xchar type;
Xint num;
Xchar *str;
X{
X line = (struct liner *)malloc(sizeof (struct liner) + strlen(str));
X if (!line) {
X fprintf(stderr, "Out of memory!\n");
X exit(1);
X }
X line->type = type;
X line->num = num;
X strcpy(line->str, str);
X line->link = hold->link;
X hold->link = line;
X hold = line;
X}
X
Xvoid
Xgenerate_output()
X{
X if (o_last < 0) {
X return;
X }
X if (output_type == 1) {
X int i, j;
X
X i = o_first ? o_last - o_first + 1 : 0;
X j = n_first ? n_last - n_first + 1 : 0;
X printf("@@ -%ld,%ld +%ld,%ld @@\n", o_first, i, n_first, j);
X for (line = root.link; line; line = hold) {
X printf("%c%s", patch_format && line->type == ' '? '=' : line->type,
X line->str);
X hold = line->link;
X free(line);
X }
X } else { /* if output == 2 */
X struct liner *scan;
X int found_plus = 1;
X char ch;
X
X printf("***************\n*** %ld", o_first);
X if (o_first == o_last) {
X printf(" ****\n");
X } else {
X printf(",%ld ****\n", o_last);
X }
X for (line = root.link; line; line = line->link) {
X if (line->type == '-') {
X break;
X }
X }
X if (line) {
X found_plus = 0;
X ch = ' ';
X for (line = root.link; line; line = line->link) {
X switch (line->type) {
X case '-':
X if (ch != ' ') {
X break;
X }
X scan = line;
X while ((scan = scan->link) != NULL && scan->type == '-') {
X ;
X }
X if (scan && scan->type == '+') {
X do {
X scan->type = '!';
X } while ((scan = scan->link) && scan->type == '+');
X ch = '!';
X } else {
X ch = '-';
X }
X break;
X case '+':
X case '!':
X found_plus = 1;
X continue;
X case ' ':
X ch = ' ';
X break;
X }
X printf("%c %s", ch, line->str);
X }/* for */
X }/* if */
X if (n_first == n_last) {
X printf("--- %ld ----\n", n_first);
X } else {
X printf("--- %ld,%ld ----\n", n_first, n_last);
X }
X if (found_plus) {
X for (line = root.link; line; line = line->link) {
X if (line->type != '-') {
X printf("%c %s", line->type, line->str);
X }
X }
X }
X for (line = root.link; line; line = hold) {
X hold = line->link;
X free(line);
X }
X }/* if output == 2 */
X
X root.link = NULL;
X head = &root;
X hold = &root;
X
X o_first = 0;
X n_first = 0;
X o_last = -1;
X n_last = 0;
X}
SHAR_EOF
fi
echo shar: "extracting 'unify.1'" '(2370 characters)'
if test -f 'unify.1'
then
echo shar: "will not over-write existing file 'unify.1'"
else
sed 's/^X//' << \SHAR_EOF > 'unify.1'
X'''
X''' unify.1
X'''
X.de Sp
X.if t .sp .5v
X.if n .sp
X..
X'''
X''' Set up \*(-- to give an unbreakable dash;
X''' string Tr holds user defined translation string.
X''' Bell System Logo is used as a dummy character.
X'''
X.tr \(bs-|\(bv\*(Tr
X.ie n \{\
X.ds -- \(bs-
X.if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch
X.if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch
X.ds L" ""
X.ds R" ""
X.ds L' '
X.ds R' '
X'br\}
X.el\{\
X.ds -- \(em\|
X.tr \*(Tr
X.ds L" ``
X.ds R" ''
X.ds L' `
X.ds R' '
X'br\}
X.TH UNIFY 1 LOCAL
X.SH NAME
Xunify - turns context diffs into unidiffs and visa versa
X.SH SYNOPSIS
X.B unify
X[-cepPsuU] [filename]
X.SH DESCRIPTION
X.I Unify
Xwill accept either a regular context diff (old- or new-style) or a unified
Xcontext diff (aka unidiff) as input, and generate either a unidiff or a
Xnew-style context diff as output.
XThe default is to output the opposite style of whatever was input, but this
Xcan be overridden by the
X.B \-c
Xor
X.B \-u
Xoptions.
XIf the source file is not mentioned, it will be read from the standard input.
X.Sp
XVarious other options allow you to echo the non-diff (comment) lines, modify
Xthe diff by removing the comment lines, and/or tweak the diff into a format
Xthat is good for releasing patches.
X.SH OPTIONS
X.TP 5
X.B \-c
Xforces context diff output.
X.TP 5
X.B \-e
Xechoes non-diff (comment) lines.
XIf a comment line is being stripped via the
X.B \-p
Xoption, it is echoed with a preceding \*(L"!!! \*(R".
XIf all comments are being stripped (via the
X.B \-s
Xoption), no special designation is given.
X.TP 5
X.B \-p
Xturns on patch-output mode. This will do three things:
X.Sp
Xa) transform a header like:
X.Sp
X *** orig/file Sat May 5 02:59:37 1990
X.br
X --- ./file Sat May 5 03:00:08 1990
X.Sp
Xinto a line of \*(L"Index: file\*(R" -- we choose the shorter name and strip
Xa leading \*(L"./\*(R" sequence if present.
X.Sp
Xb) strip lines that begin with:
X.Sp
X \*(L"Only in \*(R"
X.br
X \*(L"Common subdir\*(R"
X.br
X \*(L"diff -\*(R"
X.Sp
Xc) turn on the \*(L'=\*(R' prefix in a unidiff for lines that are common
Xto both files (instead of the leading space).
X.TP 5
X.B \-P
Xis the same as
X.B \-p
X(for compatibility with gnu diff options).
X.TP 5
X.B \-s
Xstrips non-diff lines (comments).
X.TP 5
X.B \-u
Xforces unidiff output.
X.TP 5
X.B \-U
Xis the same as \-uP.
X.SH AUTHOR
XWayne Davison <davison at dri.com> (uunet!drivax!davison)
SHAR_EOF
fi
echo shar: "extracting 'unipatch.c'" '(1358 characters)'
if test -f 'unipatch.c'
then
echo shar: "will not over-write existing file 'unipatch.c'"
else
sed 's/^X//' << \SHAR_EOF > 'unipatch.c'
X/*
XA filter to turn a unidiff into a degenerate context diff (no '!'s)
Xfor patch. Author: davison at dri.com (uunet!drivax!davison).
X*/
X#include <stdio.h>
X#define ERR(a) {fputs(a,stderr);exit(1);}
Xstruct Ln {
X struct Ln *lk;
X char t;
X char s[1];
X} r,*h,*ln;
Xchar *malloc();
Xmain()
X{
Xchar bf[2048],*cp,ch;
Xlong os,ol,ns,nl,ne,lncnt=0;
Xfor(;;){
X for(;;){
X if(!fgets(bf,sizeof bf,stdin)) exit(0);
X lncnt++;
X if(!strncmp(bf,"@@ -",4)) break;
X fputs(bf,stdout);
X }
X if(sscanf(bf+4,"%ld,%ld +%ld,%ld %c",&os,&ol,&ns,&nl,&ch)!=5||ch!='@')
X goto bad;
X r.lk=0, h= &r, ne=ns+nl-1;
X printf("***************\n*** %ld,%ld ****\n",os,os+ol-(os>0));
X while(ol||nl){
X if(!fgets(bf,sizeof bf,stdin)){
X if(nl>2) ERR("Unexpected end of file.\n");
X strcpy(bf," \n");
X }
X lncnt++;
X if(*bf=='\t'||*bf=='\n')
X ch=' ', cp=bf;
X else
X ch= *bf, cp=bf+1;
X switch(ch){
X case'-':if(!ol--) goto bad;
X printf("- %s",cp);
X break;
X case'=':ch=' ';
X case' ':if(!ol--) goto bad;
X printf(" %s",cp);
X case'+':if(!nl--) goto bad;
X ln = (struct Ln*)malloc(sizeof(*ln)+strlen(cp));
X if(!ln) ERR("Out of memory!\n");
X ln->lk=0, ln->t=ch, strcpy(ln->s,cp);
X h->lk=ln, h=ln;
X break;
X default:
X bad: fprintf(stderr,"Malformed unidiff at line %ld: ",lncnt);
X ERR(bf);
X }
X }
X printf("--- %ld,%ld ----\n",ns,ne);
X for(ln=r.lk;ln;ln=h){
X printf("%c %s",ln->t,ln->s);
X h=ln->lk;
X free(ln);
X }
X}
X}
SHAR_EOF
fi
echo shar: "extracting 'gnudiff.uni'" '(7823 characters)'
if test -f 'gnudiff.uni'
then
echo shar: "will not over-write existing file 'gnudiff.uni'"
else
sed 's/^X//' << \SHAR_EOF > 'gnudiff.uni'
XIndex: version.c
XPrereq: 1.14";
X@@ -1,3 +1,3 @@
X=/* Version number of GNU diff. */
X=
X-char *version_string = "1.14";
X+char *version_string = "1.14u";
XIndex: analyze.c
X@@ -751,5 +751,5 @@
X= {
X= setup_output (files[0].name, files[1].name, depth);
X- if (output_style == OUTPUT_CONTEXT)
X+ if (output_style == OUTPUT_CONTEXT || output_patch_flag)
X= print_context_header (files);
X=
XIndex: context.c
X@@ -22,4 +22,5 @@
X=
X=static void pr_context_hunk ();
X+static void pr_unidiff_hunk ();
X=static struct change *find_hunk ();
X=static void mark_ignorable ();
X@@ -38,8 +39,19 @@
X= struct file_data *inf;
X={
X- fprintf (outfile, "*** %s\t%s", inf[0].name,
X+ if (output_patch_flag)
X+ {
X+ char *cp = strlen (inf[0].name) <= strlen (inf[1].name)
X+ ? inf[0].name : inf[1].name;
X+ if (cp[0] == '.' && cp[1] == '/')
X+ cp += 2;
X+ fprintf (outfile, "Index: %s\n", cp);
X+ }
X+ else
X+ {
X+ fprintf (outfile, "*** %s\t%s", inf[0].name,
X= ctime (&inf[0].stat.st_mtime));
X- fprintf (outfile, "--- %s\t%s", inf[1].name,
X+ fprintf (outfile, "--- %s\t%s", inf[1].name,
X= ctime (&inf[1].stat.st_mtime));
X+ }
X=}
X=
X@@ -62,5 +74,8 @@
X= find_function_last_match = -1;
X=
X- print_script (script, find_hunk, pr_context_hunk);
X+ if (unidiff_flag)
X+ print_script (script, find_hunk, pr_unidiff_hunk);
X+ else
X+ print_script (script, find_hunk, pr_context_hunk);
X=}
X=
X@@ -189,4 +204,125 @@
X=
X= print_1_line (prefix, &files[1].linbuf[i]);
X+ }
X+ }
X+}
X+
X+/* Print a pair of line numbers with a comma, translated for file FILE.
X+ If the second number is smaller, use the first in place of it.
X+
X+ Args A and B are internal line numbers.
X+ We print the translated (real) line numbers. */
X+
X+static void
X+print_unidiff_number_range (file, a, b)
X+ struct file_data *file;
X+ int a, b;
X+{
X+ int trans_a, trans_b;
X+ translate_range (file, a, b, &trans_a, &trans_b);
X+
X+ /* Note: we can have B < A in the case of a range of no lines.
X+ In this case, we should print the line number before the range,
X+ which is B. */
X+ if (trans_b < trans_a)
X+ fprintf (outfile, "%d,0", trans_b);
X+ else
X+ fprintf (outfile, "%d,%d", trans_a, trans_b - trans_a + 1);
X+}
X+
X+/* Print a portion of an edit script in unidiff format.
X+ HUNK is the beginning of the portion to be printed.
X+ The end is marked by a `link' that has been nulled out.
X+
X+ Prints out lines from both files, and precedes each
X+ line with the appropriate flag-character. */
X+
X+static void
X+pr_unidiff_hunk (hunk)
X+ struct change *hunk;
X+{
X+ int first0, last0, first1, last1, show_from, show_to, i, j, k;
X+ struct change *next;
X+ int lastline;
X+ char *function;
X+ int function_length;
X+
X+ /* Determine range of line numbers involved in each file. */
X+
X+ analyze_hunk (hunk, &first0, &last0, &first1, &last1, &show_from, &show_to);
X+
X+ if (!show_from && !show_to)
X+ return;
X+
X+ /* Include a context's width before and after. */
X+
X+ first0 = max (first0 - context, 0);
X+ first1 = max (first1 - context, 0);
X+ last0 = min (last0 + context, files[0].buffered_lines - 1);
X+ last1 = min (last1 + context, files[1].buffered_lines - 1);
X+
X+ /* If desired, find the preceding function definition line in file 0. */
X+ function = 0;
X+ if (function_regexp)
X+ find_function (&files[0], first0, &function, &function_length);
X+
X+ /* If we looked for and found a function this is part of,
X+ include its name in the header of the diff section. */
X+
X+ fprintf (outfile, "@@ -");
X+ print_unidiff_number_range (&files[0], first0, last0);
X+ fprintf (outfile, " +");
X+ print_unidiff_number_range (&files[1], first1, last1);
X+ fprintf (outfile, " @@");
X+
X+ if (function)
X+ {
X+ putc (' ', outfile);
X+ fwrite (function, 1, min (function_length - 1, 40), outfile);
X+ }
X+ putc ('\n', outfile);
X+
X+ next = hunk;
X+ i = first0;
X+ j = first1;
X+
X+ while (i <= last0 || j <= last1)
X+ {
X+
X+ /* If the line isn't a difference, output the context from file 0. */
X+
X+ if (!next || i < next->line0)
X+ {
X+ if (output_patch_flag)
X+ putc ('=', outfile);
X+ else
X+ putc (' ', outfile);
X+ print_1_line ("", &files[0].linbuf[i++]);
X+ j++;
X+ }
X+ else
X+ {
X+ /* For each difference, first output the deleted part. */
X+
X+ k = next->deleted;
X+ while (k--)
X+ {
X+ putc ('-', outfile);
X+ print_1_line ("", &files[0].linbuf[i++]);
X+ }
X+
X+ /* Then output the inserted part. */
X+
X+ k = next->inserted;
X+ while (k--)
X+ {
X+ putc ('+', outfile);
X+ print_1_line ("", &files[1].linbuf[j++]);
X+ }
X+
X+ /* We're done with this hunk, so on to the next! */
X+
X+ next = next->link;
X+
X= }
X= }
XIndex: diff.c
X@@ -96,4 +96,6 @@
X= {"expand-tabs", 0, 0, 't'},
X= {"ignore-all-space", 0, 0, 'w'},
X+ {"unidiff", 0, 0, 'u'},
X+ {"patch", 0, 0, 'P'},
X= {"version", 0, 0, 'v'},
X= {0, 0, 0, 0}
X@@ -133,4 +135,6 @@
X= ifdef_string = NULL;
X= heuristic = FALSE;
X+ unidiff_flag = 0;
X+ output_patch_flag = 0;
X= dir_start_file = NULL;
X= msg_chain = NULL;
X@@ -141,5 +145,5 @@
X=
X= while ((c = getopt_long (argc, argv,
X- "0123456789abBcC:dD:efF:hHiI:lnNpqrsS:tTvw",
X+ "0123456789abBcC:dD:efF:hHiI:lnNpPqrsS:tTuUvw",
X= longopts, &longind)) != EOF)
X= {
X@@ -284,4 +288,8 @@
X= break;
X=
X+ case 'P':
X+ output_patch_flag = 1;
X+ break;
X+
X= case 'q':
X= no_details_flag = 1;
X@@ -322,4 +330,15 @@
X= break;
X=
X+ case 'U':
X+ /* Choose patch-style unidiff. */
X+ output_patch_flag = 1;
X+
X+ /* Falls through. */
X+ case 'u':
X+ /* Output the context diff in unidiff format. */
X+ specify_style (OUTPUT_CONTEXT);
X+ unidiff_flag = 1;
X+ break;
X+
X= case 'w':
X= /* Ignore horizontal whitespace when comparing lines. */
X@@ -378,5 +397,5 @@
X={
X= fprintf (stderr, "\
X-Usage: diff [-#] [-abBcdefhHilnNprstTvw] [-C lines] [-F regexp] [-I regexp]\n\
X+Usage: diff [-#] [-abBcdefhHilnNpPrstTuUvw] [-C lines] [-F regexp] [-I regexp]\n\
X= [-S file] [-D symbol] [+ignore-blank-lines] [+context[=lines]]\n\
X= [+ifdef symbol] [+show-function-line regexp] [+speed-large-files]\n");
X@@ -388,5 +407,5 @@
X= [+rcs] [+show-c-function] [+binary] [+brief] [+recursive]\n\
X= [+report-identical-files] [+expand-tabs] [+ignore-all-space]\n\
X- [+version] path1 path2\n");
X+ [+unidiff] [+patch] [+version] path1 path2\n");
X= exit (1);
X=}
X@@ -429,5 +448,6 @@
X= char *name = name0 == 0 ? name1 : name0;
X= char *dir = name0 == 0 ? dir1 : dir0;
X- message ("Only in %s: %s\n", dir, name);
X+ if (!output_patch_flag)
X+ message ("Only in %s: %s\n", dir, name);
X= /* Return 1 so that diff_dirs will return 1 ("some files differ"). */
X= return 1;
X@@ -535,5 +555,6 @@
X= /* But don't compare dir contents one level down
X= unless -r was specified. */
X- message ("Common subdirectories: %s and %s\n",
X+ if (!output_patch_flag)
X+ message ("Common subdirectories: %s and %s\n",
X= inf[0].name, inf[1].name);
X= val = 0;
X@@ -601,5 +622,6 @@
X= {
X= char *dir = (inf[0].desc == -1) ? dir1 : dir0;
X- message ("Only in %s: %s\n", dir, name0);
X+ if (!output_patch_flag)
X+ message ("Only in %s: %s\n", dir, name0);
X= val = 1;
X= }
XIndex: diff.h
X@@ -185,4 +185,10 @@
X=EXTERN int heuristic;
X=
X+/* Do we want to output the context diff in unidiff style? */
X+EXTERN int unidiff_flag;
X+
X+/* Reduce extraneous output when they're outputting a patch. */
X+EXTERN int output_patch_flag;
X+
X=/* Name of program the user invoked (for error messages). */
X=EXTERN char * program;
XIndex: util.c
X@@ -170,5 +170,5 @@
X= /* If handling multiple files (because scanning a directory),
X= print which files the following output is about. */
X- if (depth > 0)
X+ if (depth > 0 && !output_patch_flag)
X= printf ("%s\n", name);
X= }
SHAR_EOF
fi
echo shar: "extracting 'patch.uni'" '(6767 characters)'
if test -f 'patch.uni'
then
echo shar: "will not over-write existing file 'patch.uni'"
else
sed 's/^X//' << \SHAR_EOF > 'patch.uni'
XIndex: patchlevel.h
XPrereq: 12
X@@ -1,1 +1,1 @@
X-#define PATCHLEVEL 12
X+#define PATCHLEVEL "12u"
XIndex: common.h
X@@ -135,4 +135,5 @@
X=#define ED_DIFF 3
X=#define NEW_CONTEXT_DIFF 4
X+#define UNI_DIFF 5
X=EXT int diff_type INIT(0);
X=
XIndex: patch.c
X@@ -1,4 +1,4 @@
X=char rcsid[] =
X- "$Header: patch.c,v 2.0.1.6 88/06/22 20:46:39 lwall Locked $";
X+ "$Header: patch.c,v 2.0.2.0 90/05/01 22:17:50 davison Locked $";
X=
X=/* patch - a program to apply diffs to original files
X@@ -10,4 +10,7 @@
X= *
X= * $Log: patch.c,v $
X+ * Revision 2.0.2.0 90/05/01 22:17:50 davison
X+ * patch12u: unidiff support added
X+ *
X= * Revision 2.0.1.6 88/06/22 20:46:39 lwall
X= * patch12: rindex() wasn't declared
X@@ -458,4 +461,7 @@
X= skip_rest_of_patch = TRUE;
X= break;
X+ case 'u':
X+ diff_type = UNI_DIFF;
X+ break;
X= case 'v':
X= version();
X@@ -530,6 +536,6 @@
X= LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1;
X= LINENUM newlast = newfirst + pch_repl_lines() - 1;
X- char *stars = (diff_type == NEW_CONTEXT_DIFF ? " ****" : "");
X- char *minuses = (diff_type == NEW_CONTEXT_DIFF ? " ----" : " -----");
X+ char *stars = (diff_type >= NEW_CONTEXT_DIFF ? " ****" : "");
X+ char *minuses = (diff_type >= NEW_CONTEXT_DIFF ? " ----" : " -----");
X=
X= fprintf(rejfp, "***************\n");
XIndex: patch.man
X@@ -81,5 +81,5 @@
X=.SH DESCRIPTION
X=.I Patch
X-will take a patch file containing any of the three forms of difference
X+will take a patch file containing any of the four forms of difference
X=listing produced by the
X=.I diff
X@@ -102,8 +102,10 @@
X=.BR -c ,
X=.BR -e ,
X+.BR -n ,
X=or
X-.B -n
X+.B -u
X=switch.
X-Context diffs and normal diffs are applied by the
X+Context diffs (old-style, new-style, and unified) and
X+normal diffs are applied by the
X=.I patch
X=program itself, while ed diffs are simply fed to the
X@@ -377,4 +379,9 @@
X=.sp
X=will ignore the first and second of three patches.
X+.TP 5
X+.B \-u
X+forces
X+.I patch
X+to interpret the patch file as a unified context diff (a unidiff).
X=.TP 5
X=.B \-v
XIndex: pch.c
X@@ -2,4 +2,7 @@
X= *
X= * $Log: pch.c,v $
X+ * Revision 2.0.2.0 90/05/01 22:17:51 davison
X+ * patch12u: unidiff support added
X+ *
X= * Revision 2.0.1.7 88/06/03 15:13:28 lwall
X= * patch10: Can now find patches in shar scripts.
X@@ -163,4 +166,5 @@
X= say3(" %sooks like %s to me...\n",
X= (p_base == 0L ? "L" : "The next patch l"),
X+ diff_type == UNI_DIFF ? "a unidiff" :
X= diff_type == CONTEXT_DIFF ? "a context diff" :
X= diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
X@@ -287,4 +291,13 @@
X= goto scan_exit;
X= }
X+ if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) {
X+ if (!atol(s+3))
X+ ok_to_create_file = TRUE;
X+ p_indent = indent;
X+ p_start = this_line;
X+ p_sline = p_input_line;
X+ retval = UNI_DIFF;
X+ goto scan_exit;
X+ }
X= stars_this_line = strnEQ(s, "********", 8);
X= if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line &&
X@@ -720,4 +733,146 @@
X= assert(filldst==p_end+1 || filldst==repl_beginning);
X= }
X+ }
X+ else if (diff_type == UNI_DIFF) {
X+ long line_beginning = ftell(pfp);
X+ /* file pos of the current line */
X+ Reg4 LINENUM fillsrc; /* index of old lines */
X+ Reg5 LINENUM filldst; /* index of new lines */
X+ char ch;
X+
X+ ret = pgets(buf, sizeof buf, pfp);
X+ p_input_line++;
X+ if (ret == Nullch || strnNE(buf, "@@ -", 4)) {
X+ next_intuit_at(line_beginning,p_input_line);
X+ return FALSE;
X+ }
X+ s = buf+4;
X+ if (!*s)
X+ goto malformed;
X+ p_first = (LINENUM) atol(s);
X+ while (isdigit(*s)) s++;
X+ if (*s != ',' || !*++s)
X+ goto malformed;
X+ p_ptrn_lines = (LINENUM) atol(s);
X+ while (isdigit(*s)) s++;
X+ if (*s == ' ') s++;
X+ if (*s != '+' || !*++s)
X+ goto malformed;
X+ p_newfirst = (LINENUM) atol(s);
X+ while (isdigit(*s)) s++;
X+ if (*s != ',' || !*++s)
X+ goto malformed;
X+ p_repl_lines = (LINENUM) atol(s);
X+ while (isdigit(*s)) s++;
X+ if (*s == ' ') s++;
X+ if (*s != '@')
X+ goto malformed;
X+ if (!p_first && !p_ptrn_lines)
X+ p_first = 1;
X+ p_max = p_ptrn_lines + p_repl_lines;
X+ while (p_max >= hunkmax)
X+ grow_hunkmax();
X+ p_max = hunkmax;
X+ fillsrc = 1;
X+ filldst = fillsrc + p_ptrn_lines;
X+ p_end = filldst + p_repl_lines;
X+ Sprintf(buf,"*** %ld,%ld ****\n",p_first,p_first + p_ptrn_lines - 1);
X+ p_line[0] = savestr(buf);
X+ if (out_of_mem) {
X+ p_end = -1;
X+ return FALSE;
X+ }
X+ p_char[0] = '*';
X+ Sprintf(buf,"--- %ld,%ld ----\n",p_newfirst,p_newfirst+p_repl_lines-1);
X+ p_line[filldst] = savestr(buf);
X+ if (out_of_mem) {
X+ p_end = 0;
X+ return FALSE;
X+ }
X+ p_char[filldst++] = '=';
X+ p_context = 100;
X+ context = 0;
X+ p_hunk_beg = p_input_line + 1;
X+ while (fillsrc <= p_ptrn_lines || filldst <= p_end) {
X+ line_beginning = ftell(pfp);
X+ ret = pgets(buf, sizeof buf, pfp);
X+ p_input_line++;
X+ if (ret == Nullch) {
X+ if (p_max - filldst < 3)
X+ Strcpy(buf, " \n"); /* assume blank lines got chopped */
X+ else {
X+ fatal1("Unexpected end of file in patch.\n");
X+ }
X+ }
X+ if (*buf == '\t' || *buf == '\n') {
X+ ch = ' '; /* assume the space got eaten */
X+ s = savestr(buf);
X+ }
X+ else {
X+ ch = *buf;
X+ s = savestr(buf+1);
X+ }
X+ if (out_of_mem) {
X+ while (--filldst > p_ptrn_lines)
X+ free(p_line[filldst]);
X+ p_end = fillsrc-1;
X+ return FALSE;
X+ }
X+ switch (ch) {
X+ case '-':
X+ if (fillsrc > p_ptrn_lines) {
X+ free(s);
X+ p_end = filldst-1;
X+ goto malformed;
X+ }
X+ p_char[fillsrc] = ch;
X+ p_line[fillsrc] = s;
X+ p_len[fillsrc++] = strlen(s);
X+ break;
X+ case '=':
X+ ch = ' ';
X+ /* FALL THROUGH */
X+ case ' ':
X+ if (fillsrc > p_ptrn_lines) {
X+ free(s);
X+ while (--filldst > p_ptrn_lines)
X+ free(p_line[filldst]);
X+ p_end = fillsrc-1;
X+ goto malformed;
X+ }
X+ context++;
X+ p_char[fillsrc] = ch;
X+ p_line[fillsrc] = s;
X+ p_len[fillsrc++] = strlen(s);
X+ s = savestr(s);
X+ if (out_of_mem) {
X+ while (--filldst > p_ptrn_lines)
X+ free(p_line[filldst]);
X+ p_end = fillsrc-1;
X+ return FALSE;
X+ }
X+ /* FALL THROUGH */
X+ case '+':
X+ if (filldst > p_end) {
X+ free(s);
X+ while (--filldst > p_ptrn_lines)
X+ free(p_line[filldst]);
X+ p_end = fillsrc-1;
X+ goto malformed;
X+ }
X+ p_char[filldst] = ch;
X+ p_line[filldst] = s;
X+ p_len[filldst++] = strlen(s);
X+ break;
X+ default:
X+ p_end = filldst;
X+ goto malformed;
X+ }
X+ if (ch != ' ' && context > 0) {
X+ if (context < p_context)
X+ p_context = context;
X+ context = -1000;
X+ }
X+ }/* while */
X= }
X= else { /* normal diff--fake it up */
XIndex: version.c
X@@ -24,5 +24,5 @@
X= rcsid[0] = rcsid[0];
X=#else
X- fatal3("%s\nPatch level: %d\n", rcsid, PATCHLEVEL);
X+ fatal3("%s\nPatch level: %s\n", rcsid, PATCHLEVEL);
X=#endif
X=}
SHAR_EOF
fi
exit 0
# End of shell archive
More information about the Comp.sources.misc
mailing list