1
0
Files
irix-657m-src/eoe/cmd/sdiff/sdiff.c
2022-09-29 17:59:04 +03:00

654 lines
12 KiB
C

/* Copyright (c) 1984 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
/* #ident "@(#)sdiff:sdiff.c 1.4.1.1" */
#ident "$Header: /proj/irix6.5.7m/isms/eoe/cmd/sdiff/RCS/sdiff.c,v 1.6 1997/06/23 19:31:14 pcr Exp $"
/* 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
*/
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#define LMAX LINE_MAX
#define BMAX LINE_MAX
#define STDOUT 1
#define WGUTTER 6
#define WLEN (WGUTTER * 2 + WGUTTER + 2)
#define PROMPT '%'
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 *filename();
char *malloc();
void putline(), putmid(), error(), myremove(), cmdin(), cpp(), edit();
main(argc,argv)
int argc;
char **argv;
{
extern void 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);
myremove();
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);
}
}
void
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);
}
void
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);
}
void
error(s1,s2)
char *s1, *s2;
{
fprintf(stderr,"%s: ",pgmname);
fprintf(stderr,s1,s2);
putc('\n',stderr);
myremove();
exit(2);
}
void
onintr()
{
myremove();
exit(rcode);
}
void
myremove()
{
if(ltemp)
unlink(ltemp);
if(rtemp)
unlink(rtemp);
if(temp)
unlink(temp);
}
void
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':
myremove();
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;
}
}
}
void
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);
}
void
edit(file)
char *file;
{
int i, pid;
void (*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);
}