davison@dri.com (Wayne Davison) (08/31/90)
Posting-number: Volume 14, Issue 70 Submitted-by: davison@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@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@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@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@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@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