/********************************************************************** * Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. * * All Rights Reserved. * * Reference "/usr/src/COPYRIGHT" for applicable restrictions. * **********************************************************************/ static char Sccsid[] = "@(#)sdiff.c 3.0 4/22/86"; /* System 5 static char sccsid[] = "@(#)sdiff.c 1.2"; */ /* sdiff [-l] [-s] [-w #] [-o output] file1 file2 * does side by side diff listing * -l leftside only for identical lines * -s silent; only print differences * -w # width of output * -o output interactive creation of new output commands: s silent; do not print identical lines v turn off silent l copy left side to output r copy right side to output e l call ed with left side e r call ed with right side e b call ed with cat of left and right e call ed with empty file q exit from program * functions: cmd decode diff commands put1 output left side put2 output right side putmid output gutter putline output n chars to indicated file getlen calculate length of strings with tabs cmdin read and process interactive cmds cpp copy from file to file edit call ed with file */ #define LMAX 200 #define BMAX 256 #define STDOUT 1 #define WGUTTER 6 #define WLEN (WGUTTER * 2 + WGUTTER + 2) #define PROMPT '%' #include <stdio.h> #include <ctype.h> #include <signal.h> #include <sys/types.h> #include <sys/stat.h> char BLANKS[100] = " "; char GUTTER[WGUTTER] = " "; char *DIFF = "diff -b "; char diffcmd[BMAX]; char inbuf[10]; int llen = 130; /* Default maximum line length written out */ int hlen; /* Half line length with space for gutter */ int len1; /* Calculated length of left side */ int nchars; /* Number of characters in left side - used for tab expansion */ char change = ' '; int leftonly = 0; /* if set print left side only for identical lines */ int silent = 0; /* if set do not print identical lines */ int midflg = 0; /* set after middle was output */ int rcode = 0; /* return code */ char *pgmname; char *file1; FILE *fdes1; char buf1[BMAX+1]; char *file2; FILE *fdes2; char buf2[BMAX+1]; FILE *diffdes; char diffbuf[LMAX+1]; int oflag; char *ofile; FILE *odes; char *ltemp; FILE *left; char *rtemp; FILE *right; FILE *tempdes; char *temp; int from1, to1, from2, to2; /* decoded diff cmd- left side from to; right side from, to */ int num1, num2; /*line count for left side file and right */ char *mktemp(); FILE *popen(); char *filename(); char *malloc(); main(argc,argv) int argc; char **argv; { extern onintr(); int com; register int n1, n2, n; if (signal(SIGHUP,SIG_IGN)!=SIG_IGN) signal(SIGHUP,onintr); if (signal(SIGINT,SIG_IGN)!=SIG_IGN) signal(SIGINT,onintr); if (signal(SIGPIPE,SIG_IGN)!=SIG_IGN) signal(SIGPIPE,onintr); if (signal(SIGTERM,SIG_IGN)!=SIG_IGN) signal(SIGTERM,onintr); pgmname = argv[0]; while(--argc>1 && **++argv == '-'){ switch(*++*argv){ case 'w': /* -w# instead of -w # */ if(*++*argv) llen = atoi(*argv); else { argc--; llen = atoi(*++argv); } if(llen < WLEN) error("Wrong line length %s",*argv); if(llen > LMAX) llen = LMAX; break; case 'l': leftonly++; break; case 's': silent++; break; case 'o': oflag++; argc--; ofile = *++argv; break; default: error("Illegal argument: %s",*argv); } } if(argc != 2){ fprintf(stderr,"Usage: sdiff [-l] [-s] [-o output] [-w #] file1 file2\n"); exit(2); } file1 = *argv++; file2 = *argv; file1=filename(file1,file2); file2=filename(file2,file1); hlen = (llen - WGUTTER +1)/2; if((fdes1 = fopen(file1,"r")) == NULL) error("Cannot open: %s",file1); if((fdes2 = fopen(file2,"r")) == NULL) error("Cannot open: %s",file2); if(oflag){ if(!temp) temp = mktemp("/tmp/sdiffXXXXX"); ltemp = mktemp("/tmp/sdifflXXXXX"); if((left = fopen(ltemp,"w")) == NULL) error("Cannot open temp %s",ltemp); rtemp = mktemp("/tmp/sdiffrXXXXX"); if((right = fopen(rtemp,"w")) == NULL) error("Cannot open temp file %s",rtemp); if((odes = fopen(ofile,"w")) == NULL) error("Cannot open output %s",ofile); } /* Call DIFF command */ strcpy(diffcmd,DIFF); strcat(diffcmd,file1); strcat(diffcmd," "); strcat(diffcmd,file2); diffdes = popen(diffcmd,"r"); num1 = num2 = 0; /* Read in diff output and decode commands * "change" is used to determine character to put in gutter * num1 and num2 counts the number of lines in file1 and 2 */ n = 0; while(fgets(diffbuf,LMAX,diffdes) != NULL){ change = ' '; com = cmd(diffbuf); /* handles all diff output that is not cmd lines starting with <, >, ., --- */ if(com == 0) continue; /* Catch up to from1 and from2 */ rcode = 1; n1=from1-num1; n2=from2-num2; n= n1>n2?n2:n1; if(com =='c' && n!=0) n--; if(silent) fputs(diffbuf,stdout); while(n--){ put1(); put2(); if(!silent) putc('\n',stdout); midflg = 0; } /* Process diff cmd */ switch(com){ case 'a': change = '>'; while(num2<to2){ put2(); putc('\n',stdout); midflg = 0; } break; case 'd': change = '<'; while(num1<to1){ put1(); putc('\n',stdout); midflg = 0; } break; case 'c': n1 = to1-from1; n2 = to2-from2; n = n1>n2?n2:n1; change = '|'; do { put1(); put2(); putc('\n',stdout); midflg = 0; } while(n--); change = '<'; while(num1<to1){ put1(); putc('\n',stdout); midflg = 0; } change = '>'; while(num2<to2){ put2(); putc('\n',stdout); midflg = 0; } break; default: fprintf(stderr,"cmd not found%c\n",cmd); break; } if(oflag==1 && com!=0){ cmdin(); if((left = fopen(ltemp,"w")) == NULL) error("main: Cannot open temp %s",ltemp); if((right = fopen(rtemp,"w")) == NULL) error("main: Cannot open temp %s",rtemp); } } /* put out remainder of input files */ while(put1()){ put2(); if(!silent) putc('\n',stdout); midflg = 0; } if(odes) fclose(odes); remove(); exit(rcode); } put1() { /* len1 = length of left side */ /* nchars = num of chars including tabs */ if(fgets(buf1,BMAX,fdes1) != NULL){ len1 = getlen(0,buf1); if((!silent || change != ' ') && len1 != 0) putline(stdout,buf1,nchars); if(oflag){ /*put left side either to output file if identical to right or left temp file if not */ if(change == ' ') putline(odes,buf1,strlen(buf1)); else putline(left,buf1,strlen(buf1)); } if(change != ' ') putmid(1); num1++; return(1); } else return(0); } put2() { if(fgets(buf2,BMAX,fdes2) != NULL){ getlen((hlen+WGUTTER)%8,buf2); /* if the left and right are different they are always printed. If the left and right are identical right is only printed if leftonly is not specified or silent mode is not specified or the right contains other than white space (len1 !=0) */ if(change != ' '){ /* put right side to right temp file only because left side was written to output for identical lines */ if(oflag) putline(right,buf2,strlen(buf2)); if(midflg == 0) putmid(1); putline(stdout,buf2,nchars); } else if(!silent && !leftonly && len1!=0) { if(midflg == 0) putmid(1); putline(stdout,buf2,nchars); } num2++; len1 = 0; return(1); } else { len1 = 0; return(0); } } putline(file,start,num) FILE *file; char *start; int num; { register char *cp, *end; cp = start; end = cp + num; while(cp < end) putc(*cp++,file); } cmd(start) char *start; { char *cp, *cps; int com; if(*start == '>' || *start == '<' || *start == '-' || *start == '.') return(0); cp = cps = start; while(isdigit(*cp)) cp++; from1 = atoi(cps); to1 = from1; if(*cp == ','){ cp++; cps = cp; while(isdigit(*cp)) cp++; to1 = atoi(cps); } com = *cp++; cps = cp; while(isdigit(*cp)) cp++; from2 = atoi(cps); to2 = from2; if(*cp == ','){ cp++; cps = cp; while(isdigit(*cp)) cp++; to2 = atoi(cps); } return(com); } getlen(startpos,buffer) char *buffer; int startpos; { /* get the length of the string in buffer * expand tabs to next multiple of 8 */ register char *cp; register int slen, tlen; int notspace; nchars = 0; notspace = 0; tlen = startpos; for(cp=buffer; *cp != '\n'; cp++){ if(*cp == '\t'){ slen = tlen; tlen += 8 - (tlen%8); if(tlen>=hlen) { tlen= slen; break; } nchars++; }else{ if(tlen>=hlen)break; if(!isspace(*cp)) notspace = 1; tlen++; nchars++; } } return(notspace?tlen:0); } putmid(bflag) int bflag; { /* len1 set by getlen to the possibly truncated * length of left side * hlen is length of half line */ midflg = 1; if(bflag) putline(stdout,BLANKS,(hlen-len1)); GUTTER[2] = change; putline(stdout,GUTTER,5); } error(s1,s2) char *s1, *s2; { fprintf(stderr,"%s: ",pgmname); fprintf(stderr,s1,s2); putc('\n',stderr); remove(); exit(2); } onintr() { remove(); exit(rcode); } remove() { if(ltemp) unlink(ltemp); if(rtemp) unlink(rtemp); if(temp) unlink(temp); } cmdin() { char *cp, *ename; int notacc; fclose(left); fclose(right); notacc = 1; while(notacc){ putc(PROMPT,stdout); cp = fgets(inbuf,10,stdin); switch(*cp){ case 's': silent = 1; break; case 'v': silent = 0; break; case 'q': remove(); exit(rcode); case 'l': cpp(ltemp,left,odes); notacc = 0; break; case 'r': cpp(rtemp,right,odes); notacc = 0; break; case 'e': while(*++cp == ' ') ; switch(*cp){ case 'l': case '<': notacc = 0; ename = ltemp; edit(ename); break; case 'r': case '>': notacc = 0; ename = rtemp; edit(ename); break; case 'b': case '|': if((tempdes = fopen(temp,"w")) == NULL) error("Cannot open temp file %s",temp); cpp(ltemp,left,tempdes); cpp(rtemp,right,tempdes); fclose(tempdes); notacc = 0; ename = temp; edit(ename); break; case '\n': if((tempdes=fopen(temp,"w")) == NULL) error("Cannot open temp %s",temp); fclose(tempdes); notacc = 0; ename = temp; edit(ename); break; default: fprintf(stderr,"Illegal command %s reenter\n",cp); break; } if(notacc == 0) cpp(ename,tempdes,odes); break; default: fprintf(stderr,"Illegal command reenter\n"); break; } } } cpp(from,fromdes,todes) char *from; FILE *fromdes,*todes; { char tempbuf[BMAX+1]; if((fromdes = fopen(from,"r")) == NULL) error("cpp: Cannot open %s",from); while((fgets(tempbuf,BMAX,fromdes) != NULL)) fputs(tempbuf,todes); fclose(fromdes); } edit(file) char *file; { int i, pid; int (*oldintr) (); switch(pid=fork()){ case -1: error("Cannot fork",""); case 0: execl("/bin/ed", "ed", file, 0); } oldintr = signal(SIGINT, SIG_IGN); /*ignore interrupts while in ed */ while(pid != wait(&i)) ; signal(SIGINT,oldintr); /*restore previous interrupt proc */ } char *filename(pa1, pa2) char *pa1, *pa2; { register int c; register char *a1, *b1, *a2; struct stat stbuf; a1 = pa1; a2 = pa2; if(stat(a1,&stbuf)!=-1 && ((stbuf.st_mode&S_IFMT)==S_IFDIR)) { b1 = pa1 = malloc(100); while(*b1++ = *a1++) ; b1[-1] = '/'; a1 = b1; while(*a1++ = *a2++) if(*a2 && *a2!='/' && a2[-1]=='/') a1 = b1; } else if(a1[0] == '-' && a1[1] == 0 && temp ==0) { pa1 = temp = mktemp("/tmp/sdiffXXXXX"); if((tempdes = fopen(temp,"w")) == NULL) error("Cannot open temp %s",temp); while((c=getc(stdin)) != EOF) putc(c,tempdes); fclose(tempdes); } return(pa1); }