|
|
1.1 root 1: /* sdiff [-l] [-s] [-w #] [-o output] file1 file2
2: * does side by side diff listing
3: * -l leftside only for identical lines
4: * -s silent only print differences
5: * -w # width of output
6: * -o output interactive creation of new output
7: commands:
8: s silent; do not print identical lines
9: v turn off silent
10: l copy left side to output
11: r copy right side to output
12: e l call ed with left side
13: e r call ed with right side
14: e b call ed with cat of left and right
15: e call ed with empty file
16: q exit from program
17:
18: * functions:
19: cmd decode diff commands
20: put1 output left side
21: put2 output right side
22: putmid output gutter
23: putline output n chars to indicated file
24: getlen calculate length of strings with tabs
25: cmdin read and process interactive cmds
26: cpp copy from file to file
27: edit call ed with file
28: */
29: #define LMAX 200
30: #define BMAX 256
31: #define STDOUT 1
32: #define WGUTTER 6
33: #define WLEN 20 /* WGUTTER * 2 + WGUTTER + 2 */
34: #define PROMPT '%'
35: #include <stdio.h>
36: #include <ctype.h>
37: #include <signal.h>
38: #include <sys/types.h>
39: #include <sys/stat.h>
40:
41: char BLANKS[100] = " ";
42: char GUTTER[WGUTTER] = " ";
43: char *DIFF = "diff -b ";
44: char diffcmd[BMAX];
45: char inbuf[10];
46:
47: int llen = 130; /* Default maximum line length written out */
48: int hlen; /* Half line length with space for gutter */
49: int len1; /* Calculated length of left side */
50: int nchars; /* Number of characters in left side - used for tab expansion */
51: char change = ' ';
52: int leftonly = 0; /* if set print left side only for identical lines */
53: int silent = 0; /* if set do not print identical lines */
54: int midflg = 0; /* set after middle was output */
55:
56: char *pgmname;
57:
58: char *file1;
59: FILE *fdes1;
60: char buf1[BMAX+1];
61:
62: char *file2;
63: FILE *fdes2;
64: char buf2[BMAX+1];
65:
66: FILE *diffdes;
67: char diffbuf[LMAX+1];
68:
69: int oflag;
70: char *ofile;
71: FILE *odes;
72:
73: char *ltemp;
74: FILE *left;
75:
76: char *rtemp;
77: FILE *right;
78:
79: FILE *tempdes;
80: char *temp;
81:
82: int from1, to1, from2, to2; /* decoded diff cmd- left side from to; right side from, to */
83: int num1, num2; /*line count for left side file and right */
84:
85: char *mktemp();
86: FILE *popen();
87: char *filename();
88: char *malloc();
89:
90: main(argc,argv)
91: int argc;
92: char **argv;
93: {
94: extern onintr();
95: int com;
96: register int n1, n2, n;
97:
98: signal(SIGHUP,onintr);
99: signal(SIGINT,onintr);
100: signal(SIGPIPE,onintr);
101: signal(SIGTERM,onintr);
102: pgmname = argv[0];
103: while(--argc>1 && **++argv == '-'){
104: switch(*++*argv){
105:
106: case 'w':
107: /* -w# instead of -w # */
108: if(*++*argv)
109: llen = atoi(*argv);
110: else {
111: argc--;
112: llen = atoi(*++argv);
113: }
114: if(llen < WLEN)
115: error("Wrong line length %s",*argv);
116: if(llen > LMAX)
117: llen = LMAX;
118: break;
119:
120: case 'l':
121: leftonly++;
122: break;
123:
124: case 's':
125: silent++;
126: break;
127: case 'o':
128: oflag++;
129: argc--;
130: ofile = *++argv;
131: break;
132: default:
133: error("Illegal argument: %s",*argv);
134: }
135: }
136: if(argc != 2){
137: fprintf(stderr,"Usage: sdiff [-l] [-s] [-o output] [-w #] file1 file2\n");
138: exit(1);
139: }
140:
141: file1 = *argv++;
142: file2 = *argv;
143: file1=filename(file1,file2);
144: file2=filename(file2,file1);
145: hlen = (llen - WGUTTER +1)/2;
146:
147: if((fdes1 = fopen(file1,"r")) == NULL)
148: error("Cannot open: %s",file1);
149:
150: if((fdes2 = fopen(file2,"r")) == NULL)
151: error("Cannot open: %s",file2);
152:
153: if(oflag){
154: if(!temp)
155: temp = mktemp("/tmp/sdiffXXXXX");
156: ltemp = mktemp("/tmp/sdifflXXXXX");
157: if((left = fopen(ltemp,"w")) == NULL)
158: error("Cannot open temp %s",ltemp);
159: rtemp = mktemp("/tmp/sdiffrXXXXX");
160: if((right = fopen(rtemp,"w")) == NULL)
161: error("Cannot open temp file %s",rtemp);
162: if((odes = fopen(ofile,"w")) == NULL)
163: error("Cannot open output %s",ofile);
164: }
165: /* Call DIFF command */
166: strcpy(diffcmd,DIFF);
167: strcat(diffcmd,file1);
168: strcat(diffcmd," ");
169: strcat(diffcmd,file2);
170: diffdes = popen(diffcmd,"r");
171:
172: num1 = num2 = 0;
173:
174: /* Read in diff output and decode commands
175: * "change" is used to determine character to put in gutter
176: * num1 and num2 counts the number of lines in file1 and 2
177: */
178:
179: n = 0;
180: while(fgets(diffbuf,LMAX,diffdes) != NULL){
181: change = ' ';
182: com = cmd(diffbuf);
183:
184: /* handles all diff output that is not cmd
185: lines starting with <, >, ., --- */
186: if(com == 0)
187: continue;
188:
189: /* Catch up to from1 and from2 */
190: n1=from1-num1;
191: n2=from2-num2;
192: n= n1>n2?n2:n1;
193: if(com =='c' && n!=0)
194: n--;
195: if(silent)
196: fputs(diffbuf,stdout);
197: while(n--){
198: put1();
199: put2();
200: if(!silent)
201: putc('\n',stdout);
202: midflg = 0;
203: }
204:
205: /* Process diff cmd */
206: switch(com){
207:
208: case 'a':
209: change = '>';
210: while(num2<to2){
211: put2();
212: putc('\n',stdout);
213: midflg = 0;
214: }
215: break;
216:
217: case 'd':
218: change = '<';
219: while(num1<to1){
220: put1();
221: putc('\n',stdout);
222: midflg = 0;
223: }
224: break;
225:
226: case 'c':
227: n1 = to1-from1;
228: n2 = to2-from2;
229: n = n1>n2?n2:n1;
230: change = '|';
231: do {
232: put1();
233: put2();
234: putc('\n',stdout);
235: midflg = 0;
236: } while(n--);
237:
238: change = '<';
239: while(num1<to1){
240: put1();
241: putc('\n',stdout);
242: midflg = 0;
243: }
244:
245: change = '>';
246: while(num2<to2){
247: put2();
248: putc('\n',stdout);
249: midflg = 0;
250: }
251: break;
252:
253: default:
254: fprintf(stderr,"cmd not found%c\n",cmd);
255: break;
256: }
257:
258: if(oflag==1 && com!=0){
259: cmdin();
260: if((left = fopen(ltemp,"w")) == NULL)
261: error("main: Cannot open temp %s",ltemp);
262: if((right = fopen(rtemp,"w")) == NULL)
263: error("main: Cannot open temp %s",rtemp);
264: }
265: }
266: /* put out remainder of input files */
267: while(put1()){
268: put2();
269: if(!silent)
270: putc('\n',stdout);
271: midflg = 0;
272: }
273: if(odes)
274: fclose(odes);
275: remove();
276: exit(0);
277: }
278:
279: put1()
280: {
281: /* len1 = length of left side */
282: /* nchars = num of chars including tabs */
283:
284:
285: if(fgets(buf1,BMAX,fdes1) != NULL){
286: len1 = getlen(0,buf1);
287: if((!silent || change != ' ') && len1 != 0)
288: putline(stdout,buf1,nchars);
289:
290: if(oflag){
291: /*put left side either to output file
292: if identical to right
293: or left temp file if not */
294:
295: if(change == ' ')
296: putline(odes,buf1,strlen(buf1));
297: else
298: putline(left,buf1,strlen(buf1));
299: }
300: if(change != ' ')
301: putmid(1);
302: num1++;
303: return(1);
304: } else
305: return(0);
306: }
307:
308: put2()
309: {
310:
311: if(fgets(buf2,BMAX,fdes2) != NULL){
312: getlen((hlen+WGUTTER)%8,buf2);
313:
314: /* if the left and right are different they are always
315: printed.
316: If the left and right are identical
317: right is only printed if leftonly is not specified
318: or silent mode is not specified
319: or the right contains other than white space (len1 !=0)
320: */
321: if(change != ' '){
322:
323: /* put right side to right temp file only
324: because left side was written to output for
325: identical lines */
326:
327: if(oflag)
328: putline(right,buf2,strlen(buf2));
329:
330: if(midflg == 0)
331: putmid(1);
332: putline(stdout,buf2,nchars);
333: } else
334: if(!silent && !leftonly && len1!=0) {
335: if(midflg == 0)
336: putmid(1);
337: putline(stdout,buf2,nchars);
338: }
339: num2++;
340: len1 = 0;
341: return(1);
342: } else {
343: len1 = 0;
344: return(0);
345: }
346: }
347:
348: putline(file,start,num)
349: FILE *file;
350: char *start;
351: int num;
352: {
353:
354: register char *cp, *end;
355:
356: cp = start;
357: end = cp + num;
358: while(cp < end)
359: putc(*cp++,file);
360: }
361:
362: cmd(start)
363: char *start;
364: {
365:
366: char *cp, *cps;
367: int com;
368:
369: if(*start == '>' || *start == '<' || *start == '-' || *start == '.')
370: return(0);
371:
372: cp = cps = start;
373: while(isdigit(*cp))
374: cp++;
375: from1 = atoi(cps);
376: to1 = from1;
377: if(*cp == ','){
378: cp++;
379: cps = cp;
380: while(isdigit(*cp))
381: cp++;
382: to1 = atoi(cps);
383: }
384:
385: com = *cp++;
386: cps = cp;
387:
388: while(isdigit(*cp))
389: cp++;
390: from2 = atoi(cps);
391: to2 = from2;
392: if(*cp == ','){
393: cp++;
394: cps = cp;
395: while(isdigit(*cp))
396: cp++;
397: to2 = atoi(cps);
398: }
399: return(com);
400: }
401:
402: getlen(startpos,buffer)
403: char *buffer;
404: int startpos;
405: {
406: /* get the length of the string in buffer
407: * expand tabs to next multiple of 8
408: */
409:
410: register char *cp;
411: register int slen, tlen;
412: int notspace;
413:
414: nchars = 0;
415: notspace = 0;
416: tlen = startpos;
417: for(cp=buffer; *cp != '\n'; cp++){
418: if(*cp == '\t'){
419: slen = tlen;
420: tlen += 8 - (tlen%8);
421: if(tlen>=hlen) {
422: tlen= slen;
423: break;
424: }
425: nchars++;
426: }else{
427: if(tlen>=hlen)break;
428: if(!isspace(*cp))
429: notspace = 1;
430: tlen++;
431: nchars++;
432: }
433: }
434: return(notspace?tlen:0);
435: }
436:
437: putmid(bflag)
438: int bflag;
439: {
440: /* len1 set by getlen to the possibly truncated
441: * length of left side
442: * hlen is length of half line
443: */
444:
445:
446: midflg = 1;
447: if(bflag)
448: putline(stdout,BLANKS,(hlen-len1));
449: GUTTER[2] = change;
450: putline(stdout,GUTTER,5);
451: }
452:
453: error(s1,s2)
454: char *s1, *s2;
455: {
456: fprintf(stderr,"%s: ",pgmname);
457: fprintf(stderr,s1,s2);
458: putc('\n',stderr);
459: remove();
460: exit(1);
461: }
462:
463: onintr()
464: {
465: remove();
466: exit(1);
467: }
468:
469: remove()
470: {
471: if(ltemp)
472: unlink(ltemp);
473: if(rtemp)
474: unlink(rtemp);
475: if(temp)
476: unlink(temp);
477: }
478:
479: cmdin()
480: {
481: char *cp, *ename;
482: int notacc;
483:
484: fclose(left);
485: fclose(right);
486: notacc = 1;
487: while(notacc){
488: putc(PROMPT,stdout);
489: cp = fgets(inbuf,10,stdin);
490: switch(*cp){
491:
492: case 's':
493: silent = 1;
494: break;
495:
496: case 'v':
497: silent = 0;
498: break;
499:
500: case 'q':
501: remove();
502: exit(0);
503:
504: case 'l':
505: cpp(ltemp,left,odes);
506: notacc = 0;
507: break;
508:
509: case 'r':
510: cpp(rtemp,right,odes);
511: notacc = 0;
512: break;
513:
514: case 'e':
515: while(*++cp == ' ')
516: ;
517: switch(*cp){
518: case 'l':
519: case '<':
520: notacc = 0;
521: ename = ltemp;
522: edit(ename);
523: break;
524:
525: case 'r':
526: case '>':
527: notacc = 0;
528: ename = rtemp;
529: edit(ename);
530: break;
531:
532: case 'b':
533: case '|':
534: if((tempdes = fopen(temp,"w")) == NULL)
535: error("Cannot open temp file %s",temp);
536: cpp(ltemp,left,tempdes);
537: cpp(rtemp,right,tempdes);
538: fclose(tempdes);
539: notacc = 0;
540: ename = temp;
541: edit(ename);
542: break;
543:
544: case '\n':
545: if((tempdes=fopen(temp,"w")) == NULL)
546: error("Cannot open temp %s",temp);
547: fclose(tempdes);
548: notacc = 0;
549: ename = temp;
550: edit(ename);
551: break;
552: default:
553: fprintf(stderr,"Illegal command %s reenter\n",cp);
554: break;
555: }
556: if(notacc == 0)
557: cpp(ename,tempdes,odes);
558: break;
559:
560: default:
561: fprintf(stderr,"Illegal command reenter\n");
562: break;
563: }
564: }
565: }
566:
567: cpp(from,fromdes,todes)
568: char *from;
569: FILE *fromdes,*todes;
570: {
571: char tempbuf[BMAX+1];
572:
573: if((fromdes = fopen(from,"r")) == NULL)
574: error("cpp: Cannot open %s",from);
575: while((fgets(tempbuf,BMAX,fromdes) != NULL))
576: fputs(tempbuf,todes);
577: fclose(fromdes);
578: }
579:
580: edit(file)
581: char *file;
582: {
583: int i, pid;
584:
585: int (*oldintr) ();
586:
587: switch(pid=fork()){
588:
589: case -1:
590: error("Cannot fork","");
591: case 0:
592: execl("/bin/ed", "ed", file, 0);
593: }
594:
595: oldintr = signal(SIGINT, SIG_IGN); /*ignore interrupts while in ed */
596: while(pid != wait(&i))
597: ;
598: signal(SIGINT,oldintr); /*restore previous interrupt proc */
599: }
600:
601: char *filename(pa1, pa2)
602: char *pa1, *pa2;
603: {
604: register int c;
605: register char *a1, *b1, *a2;
606: struct stat stbuf;
607: a1 = pa1;
608: a2 = pa2;
609: if(stat(a1,&stbuf)!=-1 && ((stbuf.st_mode&S_IFMT)==S_IFDIR)) {
610: b1 = pa1 = malloc(100);
611: while(*b1++ = *a1++) ;
612: b1[-1] = '/';
613: a1 = b1;
614: while(*a1++ = *a2++)
615: if(*a2 && *a2!='/' && a2[-1]=='/')
616: a1 = b1;
617: }
618: else if(a1[0] == '-' && a1[1] == 0 && temp ==0) {
619: pa1 = temp = mktemp("/tmp/sdiffXXXXX");
620: if((tempdes = fopen(temp,"w")) == NULL)
621: error("Cannot open temp %s",temp);
622: while((c=getc(stdin)) != EOF)
623: putc(c,tempdes);
624: fclose(tempdes);
625: }
626: return(pa1);
627: }
628:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.