📄 rcsdiff.c
字号:
/* * RCS rcsdiff operation *//***************************************************************************** * generate difference between RCS revisions ***************************************************************************** *//* Copyright (C) 1982, 1988, 1989 Walter Tichy Copyright 1990, 1991 by Paul Eggert Distributed under license by the Free Software Foundation, Inc.This file is part of RCS.RCS is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.RCS is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with RCS; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.Report problems and direct all questions to: rcs-bugs@cs.purdue.edu*//* $Log: rcsdiff.c,v $ * Revision 5.10 1991/10/07 17:32:46 eggert * Remove lint. * * Revision 5.9 1991/08/19 03:13:55 eggert * Add RCSINIT, -r$. Tune. * * Revision 5.8 1991/04/21 11:58:21 eggert * Add -x, RCSINIT, MS-DOS support. * * Revision 5.7 1990/12/13 06:54:07 eggert * GNU diff 1.15 has -u. * * Revision 5.6 1990/11/01 05:03:39 eggert * Remove unneeded setid check. * * Revision 5.5 1990/10/04 06:30:19 eggert * Accumulate exit status across files. * * Revision 5.4 1990/09/27 01:31:43 eggert * Yield 1, not EXIT_FAILURE, when diffs are found. * * Revision 5.3 1990/09/11 02:41:11 eggert * Simplify -kkvl test. * * Revision 5.2 1990/09/04 17:07:19 eggert * Diff's argv was too small by 1. * * Revision 5.1 1990/08/29 07:13:55 eggert * Add -kkvl. * * Revision 5.0 1990/08/22 08:12:46 eggert * Add -k, -V. Don't use access(). Add setuid support. * Remove compile-time limits; use malloc instead. * Don't pass arguments with leading '+' to diff; GNU DIFF treats them as options. * Add GNU diff's flags. Make lock and temp files faster and safer. * Ansify and Posixate. * * Revision 4.6 89/05/01 15:12:27 narten * changed copyright header to reflect current distribution rules * * Revision 4.5 88/08/09 19:12:41 eggert * Use execv(), not system(); yield exit status like diff(1)s; allow cc -R. * * Revision 4.4 87/12/18 11:37:46 narten * changes Jay Lepreau made in the 4.3 BSD version, to add support for * "-i", "-w", and "-t" flags and to permit flags to be bundled together, * merged in. * * Revision 4.3 87/10/18 10:31:42 narten * Updating version numbers. Changes relative to 1.1 actually * relative to 4.1 * * Revision 1.3 87/09/24 13:59:21 narten * Sources now pass through lint (if you ignore printf/sprintf/fprintf * warnings) * * Revision 1.2 87/03/27 14:22:15 jenkins * Port to suns * * Revision 4.1 83/05/03 22:13:19 wft * Added default branch, option -q, exit status like diff. * Added fterror() to replace faterror(). * * Revision 3.6 83/01/15 17:52:40 wft * Expanded mainprogram to handle multiple RCS files. * * Revision 3.5 83/01/06 09:33:45 wft * Fixed passing of -c (context) option to diff. * * Revision 3.4 82/12/24 15:28:38 wft * Added call to catchsig(). * * Revision 3.3 82/12/10 16:08:17 wft * Corrected checking of return code from diff; improved error msgs. * * Revision 3.2 82/12/04 13:20:09 wft * replaced getdelta() with gettree(). Changed diagnostics. * * Revision 3.1 82/11/28 19:25:04 wft * Initial revision. * */#include "rcsbase.h"#if DIFF_Lstatic char const *setup_label P((struct buf*,char const*,char const[datesize]));#endifstatic void cleanup P((void));static int exitstatus;static RILE *workptr;static struct stat workstat;mainProg(rcsdiffId, "rcsdiff", "$Id: rcsdiff.c,v 5.10 1991/10/07 17:32:46 eggert Exp $"){ static char const cmdusage[] = "\nrcsdiff usage: rcsdiff [-q] [-rrev1 [-rrev2]] [-Vn] [diff options] file ..."; int revnums; /* counter for revision numbers given */ char const *rev1, *rev2; /* revision numbers from command line */ char const *xrev1, *xrev2; /* expanded revision numbers */ char const *expandarg, *lexpandarg, *versionarg;#if DIFF_L static struct buf labelbuf[2]; int file_labels; char const **diff_label1, **diff_label2; char date2[datesize];#endif char const *cov[9]; char const **diffv, **diffp; /* argv for subsidiary diff */ char const **pp, *p, *diffvstr; struct buf commarg; struct buf numericrev; /* expanded revision number */ struct hshentries *gendeltas; /* deltas to be generated */ struct hshentry * target; char *a, *dcp, **newargv; register c; exitstatus = DIFF_SUCCESS; bufautobegin(&commarg); bufautobegin(&numericrev); revnums = 0; rev1 = rev2 = xrev2 = nil;#if DIFF_L file_labels = 0;#endif expandarg = versionarg = 0; suffixes = X_DEFAULT; /* Room for args + 2 i/o [+ 2 labels] + 1 file + 1 trailing null. */ diffp = diffv = tnalloc(char const*, argc + 4 + 2*DIFF_L); *diffp++ = nil; *diffp++ = nil; *diffp++ = DIFF; argc = getRCSINIT(argc, argv, &newargv); argv = newargv; while (a = *++argv, 0<--argc && *a++=='-') { dcp = a; while (c = *a++) switch (c) { case 'r': switch (++revnums) { case 1: rev1=a; break; case 2: rev2=a; break; default: faterror("too many revision numbers"); } goto option_handled;#if DIFF_L case 'L': if (++file_labels == 2) faterror("too many -L options"); /* fall into */#endif case 'C': case 'D': case 'F': case 'I': *dcp++ = c; if (*a) do *dcp++ = *a++; while (*a); else { if (!--argc) faterror("-%c needs following argument%s", c, cmdusage ); *diffp++ = *argv++; } break; case 'B': case 'H': case 'T': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'h': case 'i': case 'n': case 'p': case 't': case 'u': case 'w': *dcp++ = c; break; case 'q': quietflag=true; break; case 'x': suffixes = *argv + 2; goto option_handled; case 'V': versionarg = *argv; setRCSversion(versionarg); goto option_handled; case 'k': expandarg = *argv; if (0 <= str2expmode(expandarg+2)) goto option_handled; /* fall into */ default: faterror("unknown option: %s%s", *argv, cmdusage); }; option_handled: if (dcp != *argv+1) { *dcp = 0; *diffp++ = *argv; } } /* end of option processing */ if (argc<1) faterror("no input file%s", cmdusage); for (pp = diffv+3, c = 0; pp<diffp; ) c += strlen(*pp++) + 1; diffvstr = a = tnalloc(char, c + 1); for (pp = diffv+3; pp<diffp; ) { p = *pp++; *a++ = ' '; while ((*a = *p++)) a++; } *a = 0;#if DIFF_L diff_label1 = diff_label2 = nil; if (file_labels < 2) { if (!file_labels) diff_label1 = diffp++; diff_label2 = diffp++; }#endif diffp[2] = nil; cov[0] = 0; cov[2] = CO; cov[3] = "-q"; /* now handle all filenames */ do { ffree(); if (pairfilenames(argc, argv, rcsreadopen, true, false) <= 0) continue; diagnose("===================================================================\nRCS file: %s\n",RCSfilename); if (!rev2) { /* Make sure work file is readable, and get its status. */ if (!(workptr = Iopen(workfilename,FOPEN_R_WORK,&workstat))) { eerror(workfilename); continue; } } gettree(); /* reads in the delta tree */ if (Head==nil) { error("no revisions present"); continue; } if (revnums==0 || !*rev1) rev1 = Dbranch ? Dbranch : Head->num; if (!fexpandsym(rev1, &numericrev, workptr)) continue; if (!(target=genrevs(numericrev.string,(char *)nil,(char *)nil,(char *)nil,&gendeltas))) continue; xrev1=target->num;#if DIFF_L if (diff_label1) *diff_label1 = setup_label(&labelbuf[0], target->num, target->date);#endif lexpandarg = expandarg; if (revnums==2) { if (!fexpandsym( *rev2 ? rev2 : Dbranch ? Dbranch : Head->num, &numericrev, workptr )) continue; if (!(target=genrevs(numericrev.string,(char *)nil,(char *)nil,(char *)nil,&gendeltas))) continue; xrev2=target->num; } else if ( target->lockedby && !lexpandarg && Expand == KEYVAL_EXPAND && WORKMODE(RCSstat.st_mode,true) == workstat.st_mode ) lexpandarg = "-kkvl"; Izclose(&workptr);#if DIFF_L if (diff_label2) if (revnums == 2) *diff_label2 = setup_label(&labelbuf[1], target->num, target->date); else { time2date(workstat.st_mtime, date2); *diff_label2 = setup_label(&labelbuf[1], workfilename, date2); }#endif diagnose("retrieving revision %s\n", xrev1); bufscpy(&commarg, "-p"); bufscat(&commarg, xrev1); cov[1] = diffp[0] = maketemp(0); pp = &cov[4]; *pp++ = commarg.string; if (lexpandarg) *pp++ = lexpandarg; if (versionarg) *pp++ = versionarg; *pp++ = RCSfilename; *pp = 0; if (runv(cov)) { error("co failed"); continue; } if (!rev2) { diffp[1] = workfilename; if (workfilename[0] == '+') { /* Some diffs have options with leading '+'. */ char *dp = ftnalloc(char, strlen(workfilename)+3); diffp[1] = dp; *dp++ = '.'; *dp++ = SLASH; VOID strcpy(dp, workfilename); } } else { diagnose("retrieving revision %s\n",xrev2); bufscpy(&commarg, "-p"); bufscat(&commarg, xrev2); cov[1] = diffp[1] = maketemp(1); cov[4] = commarg.string; if (runv(cov)) { error("co failed"); continue; } } if (!rev2) diagnose("diff%s -r%s %s\n", diffvstr, xrev1, workfilename); else diagnose("diff%s -r%s -r%s\n", diffvstr, xrev1, xrev2); switch (runv(diffv)) { case DIFF_SUCCESS: break; case DIFF_FAILURE: if (exitstatus == DIFF_SUCCESS) exitstatus = DIFF_FAILURE; break; default: error("diff failed"); } } while (cleanup(), ++argv, --argc >=1); tempunlink(); exitmain(exitstatus);} static voidcleanup(){ if (nerror) exitstatus = DIFF_TROUBLE; Izclose(&finptr); Izclose(&workptr);}#if lint# define exiterr rdiffExit#endif exiting voidexiterr(){ tempunlink(); _exit(DIFF_TROUBLE);}#if DIFF_L static char const *setup_label(b, name, date) struct buf *b; char const *name; char const date[datesize];{ char *p; size_t l = strlen(name) + 3; bufalloc(b, l+datesize); p = b->string; VOID sprintf(p, "-L%s\t", name); VOID date2str(date, p+l); return p;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -