1: /* 2: * RCS rcsdiff operation 3: */ 4: #ifndef lint 5: static char rcsid[]= 6: "$Header: /usr/src/new/rcs/src/RCS/rcsdiff.c,v 3.9 88/02/18 11:55:57 bostic Exp $ Purdue CS"; 7: #endif 8: /***************************************************************************** 9: * generate difference between RCS revisions 10: ***************************************************************************** 11: * 12: * Copyright (C) 1982 by Walter F. Tichy 13: * Purdue University 14: * Computer Science Department 15: * West Lafayette, IN 47907 16: * 17: * All rights reserved. No part of this software may be sold or distributed 18: * in any form or by any means without the prior written permission of the 19: * author. 20: * Report problems and direct all inquiries to Tichy@purdue (ARPA net). 21: */ 22: 23: 24: /* $Log: rcsdiff.c,v $ 25: * Revision 3.9 88/02/18 11:55:57 bostic 26: * replaced with version 4 27: * 28: * Revision 4.4 87/12/18 11:37:46 narten 29: * changes Jay Lepreau made in the 4.3 BSD version, to add support for 30: * "-i", "-w", and "-t" flags and to permit flags to be bundled together, 31: * merged in. 32: * 33: * Revision 4.3 87/10/18 10:31:42 narten 34: * Updating version numbers. Changes relative to 1.1 actually 35: * relative to 4.1 36: * 37: * Revision 1.3 87/09/24 13:59:21 narten 38: * Sources now pass through lint (if you ignore printf/sprintf/fprintf 39: * warnings) 40: * 41: * Revision 1.2 87/03/27 14:22:15 jenkins 42: * Port to suns 43: * 44: * Revision 1.1 84/01/23 14:50:18 kcs 45: * Initial revision 46: * 47: * Revision 4.1 83/05/03 22:13:19 wft 48: * Added default branch, option -q, exit status like diff. 49: * Added fterror() to replace faterror(). 50: * 51: * Revision 3.6 83/01/15 17:52:40 wft 52: * Expanded mainprogram to handle multiple RCS files. 53: * 54: * Revision 3.5 83/01/06 09:33:45 wft 55: * Fixed passing of -c (context) option to diff. 56: * 57: * Revision 3.4 82/12/24 15:28:38 wft 58: * Added call to catchsig(). 59: * 60: * Revision 3.3 82/12/10 16:08:17 wft 61: * Corrected checking of return code from diff; improved error msgs. 62: * 63: * Revision 3.2 82/12/04 13:20:09 wft 64: * replaced getdelta() with gettree(). Changed diagnostics. 65: * 66: * Revision 3.1 82/11/28 19:25:04 wft 67: * Initial revision. 68: * 69: */ 70: #include <ctype.h> 71: #include "rcsbase.h" 72: #define ERRCODE 2 /*error code for exit status */ 73: #ifndef lint 74: static char rcsbaseid[] = RCSBASE; 75: #endif 76: 77: extern int cleanup(); /* cleanup after signals */ 78: extern char * mktempfile(); /*temporary file name generator */ 79: extern int fterror(); /*forward for special fatal error func. */ 80: extern struct hshentry * genrevs(); /*generate delta numbers */ 81: extern int nerror; /*counter for errors */ 82: extern int quietflag; /*suppresses diagnostics */ 83: extern FILE * finptr; /* RCS input file */ 84: 85: char *RCSfilename; 86: char *workfilename; 87: char * temp1file, * temp2file; 88: 89: char bops[10] = "-"; 90: char otherops[10] = "-"; 91: 92: main (argc, argv) 93: int argc; char **argv; 94: { 95: char * cmdusage; 96: char command[NCPPN+revlength+40]; 97: int revnums; /* counter for revision numbers given */ 98: char * rev1, * rev2; /* revision numbers from command line */ 99: char numericrev[revlength]; /* holds expanded revision number */ 100: char * xrev1, * xrev2; /* expanded revision numbers */ 101: struct hshentry * gendeltas[hshsize];/*stores deltas to be generated*/ 102: struct hshentry * target; 103: char * boption, * otheroption; 104: int exit_stats; 105: int filecounter; 106: char *argp; 107: register c; 108: 109: catchints(); 110: otheroption = otherops + 1; 111: boption = bops + 1; 112: cmdid = "rcsdiff"; 113: cmdusage = "command format:\n rcsdiff [-biwt] [-q] [-cefhn] [-rrev1] [-rrev2] file"; 114: filecounter=revnums=0; 115: while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) { 116: argp = &((*argv)[1]); 117: while (c = *argp++) switch (c) { 118: case 'r': 119: if (*argp!='\0') { 120: if (revnums==0) { 121: rev1= argp; revnums=1; 122: } elif (revnums==1) { 123: rev2= argp; revnums=2; 124: } else { 125: fterror("too many revision numbers"); 126: } 127: } /* do nothing for empty -r */ 128: argp += strlen(argp); 129: break; 130: case 'b': 131: case 'i': 132: case 'w': 133: case 't': 134: *boption++ = c; 135: break; 136: case 'q': 137: quietflag=true; 138: break; 139: case 'c': 140: case 'e': 141: case 'f': 142: case 'h': 143: case 'n': 144: if (otheroption == otherops + 1) { 145: *otheroption++ = c; 146: if (c == 'c' && isdigit(*argp)) { 147: while (isdigit(*argp)) 148: *otheroption++ = *argp++; 149: if (*argp) 150: faterror("-c: bad count"); 151: argp = ""; 152: } 153: } else { 154: fterror("Options c,e,f,h,n are mutually exclusive"); 155: } 156: break; 157: default: 158: fterror("unknown option: %s\n%s", *argv,cmdusage); 159: }; 160: } /* end of option processing */ 161: 162: if (boption != bops + 1) { 163: *boption = ' '; 164: boption = bops; 165: } 166: if (otheroption != otherops + 1) { 167: *otheroption = ' '; 168: otheroption = otherops; 169: } 170: if (argc<1) fterror("No input file\n%s",cmdusage); 171: 172: /* now handle all filenames */ 173: do { 174: finptr=NULL; 175: 176: if (pairfilenames(argc,argv,true,false)!=1) continue; 177: if (++filecounter>1) 178: diagnose("==================================================================="); 179: diagnose("RCS file: %s",RCSfilename); 180: if (revnums<2 && !(access(workfilename,4)==0)) { 181: error("Can't open %s",workfilename); 182: continue; 183: } 184: if (!trysema(RCSfilename,false)) continue; /* give up */ 185: 186: 187: gettree(); /* reads in the delta tree */ 188: 189: if (Head==nil) { 190: error("no revisions present"); 191: continue; 192: } 193: if (revnums==0) 194: rev1=Dbranch!=nil?Dbranch->num:Head->num; /* default rev1 */ 195: 196: if (!expandsym(rev1,numericrev)) continue; 197: if (!(target=genrevs(numericrev,(char *)nil,(char *)nil,(char *)nil,gendeltas))) continue; 198: xrev1=target->num; 199: 200: if (revnums==2) { 201: if (!expandsym(rev2,numericrev)) continue; 202: if (!(target=genrevs(numericrev,(char *)nil,(char *)nil,(char *)nil,gendeltas))) continue; 203: xrev2=target->num; 204: } 205: 206: 207: temp1file=mktempfile("/tmp/",TMPFILE1); 208: diagnose("retrieving revision %s",xrev1); 209: VOID sprintf(command,"%s/co -q -p%s %s > %s\n", 210: TARGETDIR,xrev1,RCSfilename,temp1file); 211: if (system(command)){ 212: error("co failed"); 213: continue; 214: } 215: if (revnums<=1) { 216: temp2file=workfilename; 217: diagnose("diff %s%s-r%s %s",boption,otheroption,xrev1,workfilename); 218: } else { 219: temp2file=mktempfile("/tmp/",TMPFILE2); 220: diagnose("retrieving revision %s",xrev2); 221: VOID sprintf(command,"%s/co -q -p%s %s > %s\n", 222: TARGETDIR,xrev2,RCSfilename,temp2file); 223: if (system(command)){ 224: error("co failed"); 225: continue; 226: } 227: diagnose("diff %s%s-r%s -r%s",boption,otheroption,xrev1,xrev2); 228: } 229: VOID sprintf(command,"%s %s%s%s %s\n",DIFF,boption, 230: otheroption, temp1file, temp2file); 231: exit_stats = system (command); 232: if (exit_stats != 0 && exit_stats != (1 << BYTESIZ)) { 233: error ("diff failed"); 234: continue; 235: } 236: } while (cleanup(), 237: ++argv, --argc >=1); 238: 239: 240: if (nerror>0) { 241: exit(ERRCODE); 242: } else { 243: exit(exit_stats>>BYTESIZ); 244: /* return exit status from diff */ 245: } 246: 247: } 248: 249: 250: /*VARARGS3*/ 251: fterror(e, e1, e2) 252: char * e, * e1, * e2; 253: /* prints error message and terminates program with ERRCODE */ 254: { nerror++; 255: VOID fprintf(stderr,"%s error: ",cmdid); 256: VOID fprintf(stderr,e, e1, e2); 257: VOID fprintf(stderr,"\n%s aborted\n",cmdid); 258: VOID cleanup(); 259: exit(ERRCODE); 260: }