📄 rcs.c
字号:
/* * RCS create/change operation *//* 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: rcs.c,v $ * Revision 5.12 1991/11/20 17:58:08 eggert * Don't read the delta tree from a nonexistent RCS file. * * Revision 5.11 1991/10/07 17:32:46 eggert * Remove lint. * * Revision 5.10 1991/08/19 23:17:54 eggert * Add -m, -r$, piece tables. Revision separator is `:', not `-'. Tune. * * Revision 5.9 1991/04/21 11:58:18 eggert * Add -x, RCSINIT, MS-DOS support. * * Revision 5.8 1991/02/25 07:12:38 eggert * strsave -> str_save (DG/UX name clash) * 0444 -> S_IRUSR|S_IRGRP|S_IROTH for portability * * Revision 5.7 1990/12/18 17:19:21 eggert * Fix bug with multiple -n and -N options. * * Revision 5.6 1990/12/04 05:18:40 eggert * Use -I for prompts and -q for diagnostics. * * Revision 5.5 1990/11/11 00:06:35 eggert * Fix `rcs -e' core dump. * * Revision 5.4 1990/11/01 05:03:33 eggert * Add -I and new -t behavior. Permit arbitrary data in logs. * * Revision 5.3 1990/10/04 06:30:16 eggert * Accumulate exit status across files. * * Revision 5.2 1990/09/04 08:02:17 eggert * Standardize yes-or-no procedure. * * Revision 5.1 1990/08/29 07:13:51 eggert * Remove unused setuid support. Clean old log messages too. * * Revision 5.0 1990/08/22 08:12:42 eggert * Don't lose names when applying -a option to multiple files. * Remove compile-time limits; use malloc instead. Add setuid support. * Permit dates past 1999/12/31. Make lock and temp files faster and safer. * Ansify and Posixate. Add -V. Fix umask bug. Make linting easier. Tune. * Yield proper exit status. Check diff's output. * * Revision 4.11 89/05/01 15:12:06 narten * changed copyright header to reflect current distribution rules * * Revision 4.10 88/11/08 16:01:54 narten * didn't install previous patch correctly * * Revision 4.9 88/11/08 13:56:01 narten * removed include <sysexits.h> (not needed) * minor fix for -A option * * Revision 4.8 88/08/09 19:12:27 eggert * Don't access freed storage. * Use execv(), not system(); yield proper exit status; remove lint. * * Revision 4.7 87/12/18 11:37:17 narten * lint cleanups (Guy Harris) * * Revision 4.6 87/10/18 10:28:48 narten * Updating verison numbers. Changes relative to 1.1 are actually * relative to 4.3 * * Revision 1.4 87/09/24 13:58:52 narten * Sources now pass through lint (if you ignore printf/sprintf/fprintf * warnings) * * Revision 1.3 87/03/27 14:21:55 jenkins * Port to suns * * Revision 1.2 85/12/17 13:59:09 albitz * Changed setstate to rcs_setstate because of conflict with random.o. * * Revision 4.3 83/12/15 12:27:33 wft * rcs -u now breaks most recent lock if it can't find a lock by the caller. * * Revision 4.2 83/12/05 10:18:20 wft * Added conditional compilation for sending mail. * Alternatives: V4_2BSD, V6, USG, and other. * * Revision 4.1 83/05/10 16:43:02 wft * Simplified breaklock(); added calls to findlock() and getcaller(). * Added option -b (default branch). Updated -s and -w for -b. * Removed calls to stat(); now done by pairfilenames(). * Replaced most catchints() calls with restoreints(). * Removed check for exit status of delivermail(). * Directed all interactive output to stderr. * * Revision 3.9.1.1 83/12/02 22:08:51 wft * Added conditional compilation for 4.2 sendmail and 4.1 delivermail. * * Revision 3.9 83/02/15 15:38:39 wft * Added call to fastcopy() to copy remainder of RCS file. * * Revision 3.8 83/01/18 17:37:51 wft * Changed sendmail(): now uses delivermail, and asks whether to break the lock. * * Revision 3.7 83/01/15 18:04:25 wft * Removed putree(); replaced with puttree() in rcssyn.c. * Combined putdellog() and scanlogtext(); deleted putdellog(). * Cleaned up diagnostics and error messages. Fixed problem with * mutilated files in case of deletions in 2 files in a single command. * Changed marking of selector from 'D' to DELETE. * * Revision 3.6 83/01/14 15:37:31 wft * Added ignoring of interrupts while new RCS file is renamed; * Avoids deletion of RCS files by interrupts. * * Revision 3.5 82/12/10 21:11:39 wft * Removed unused variables, fixed checking of return code from diff, * introduced variant COMPAT2 for skipping Suffix on -A files. * * Revision 3.4 82/12/04 13:18:20 wft * Replaced getdelta() with gettree(), changed breaklock to update * field lockedby, added some diagnostics. * * Revision 3.3 82/12/03 17:08:04 wft * Replaced getlogin() with getpwuid(), flcose() with ffclose(), * /usr/ucb/Mail with macro MAIL. Removed handling of Suffix (-x). * fixed -u for missing revno. Disambiguated structure members. * * Revision 3.2 82/10/18 21:05:07 wft * rcs -i now generates a file mode given by the umask minus write permission; * otherwise, rcs keeps the mode, but removes write permission. * I added a check for write error, fixed call to getlogin(), replaced * curdir() with getfullRCSname(), cleaned up handling -U/L, and changed * conflicting, long identifiers. * * Revision 3.1 82/10/13 16:11:07 wft * fixed type of variables receiving from getc() (char -> int). */#include "rcsbase.h"struct Lockrev { char const *revno; struct Lockrev * nextrev;};struct Symrev { char const *revno; char const *ssymbol; int override; struct Symrev * nextsym;};struct Message { char const *revno; struct cbuf message; struct Message *nextmessage;};struct Status { char const *revno; char const *status; struct Status * nextstatus;};enum changeaccess {append, erase};struct chaccess { char const *login; enum changeaccess command; struct chaccess *nextchaccess;};struct delrevpair { char const *strt; char const *end; int code;};static int buildeltatext P((struct hshentries const*));static int removerevs P((void));static int sendmail P((char const*,char const*));static struct Lockrev *rmnewlocklst P((struct Lockrev const*));static void breaklock P((struct hshentry const*));static void buildtree P((void));static void cleanup P((void));static void doaccess P((void));static void doassoc P((void));static void dolocks P((void));static void domessages P((void));static void getaccessor P((char*,enum changeaccess));static void getassoclst P((int,char*));static void getchaccess P((char const*,enum changeaccess));static void getdelrev P((char*));static void getmessage P((char*));static void getstates P((char*));static void rcs_setstate P((char const*,char const*));static void scanlogtext P((struct hshentry*,int));static void setlock P((char const*));static struct buf numrev;static char const *headstate;static int chgheadstate, exitstatus, lockhead, unlockcaller;static struct Lockrev *newlocklst, *rmvlocklst;static struct Message *messagelst, *lastmessage;static struct Status *statelst, *laststate;static struct Symrev *assoclst, *lastassoc;static struct chaccess *chaccess, **nextchaccess;static struct delrevpair delrev;static struct hshentry *cuthead, *cuttail, *delstrt;static struct hshentries *gendeltas;mainProg(rcsId, "rcs", "$Id: rcs.c,v 5.12 1991/11/20 17:58:08 eggert Exp $"){ static char const cmdusage[] = "\nrcs usage: rcs -{ae}logins -Afile -{blu}[rev] -cstring -{iLU} -{nNs}name[:rev] -orange -t[file] -Vn file ..."; char *a, **newargv, *textfile; char const *branchsym, *commsyml; int branchflag, expmode, initflag; int e, r, strictlock, strict_selected, textflag; mode_t defaultRCSmode; /* default mode for new RCS files */ mode_t RCSmode; struct buf branchnum; struct stat workstat; struct Lockrev *curlock, * rmvlock, *lockpt; struct Status * curstate; nosetid(); nextchaccess = &chaccess; branchsym = commsyml = textfile = nil; branchflag = strictlock = false; bufautobegin(&branchnum); curlock = rmvlock = nil; defaultRCSmode = 0; expmode = -1; suffixes = X_DEFAULT; initflag= textflag = false; strict_selected = 0; /* preprocessing command options */ argc = getRCSINIT(argc, argv, &newargv); argv = newargv; while (a = *++argv, 0<--argc && *a++=='-') { switch (*a++) { case 'i': /* initial version */ initflag = true; break; case 'b': /* change default branch */ if (branchflag) redefined('b'); branchflag= true; branchsym = a; break; case 'c': /* change comment symbol */ if (commsyml) redefined('c'); commsyml = a; break; case 'a': /* add new accessor */ getaccessor(*argv+1, append); break; case 'A': /* append access list according to accessfile */ if (!*a) { error("missing file name after -A"); break; } *argv = a; if (0 < pairfilenames(1,argv,rcsreadopen,true,false)) { while (AccessList) { getchaccess(str_save(AccessList->login),append); AccessList = AccessList->nextaccess; } Izclose(&finptr); } break; case 'e': /* remove accessors */ getaccessor(*argv+1, erase); break; case 'l': /* lock a revision if it is unlocked */ if (!*a) { /* Lock head or default branch. */ lockhead = true; break; } lockpt = talloc(struct Lockrev); lockpt->revno = a; lockpt->nextrev = nil; if ( curlock ) curlock->nextrev = lockpt; else newlocklst = lockpt; curlock = lockpt; break; case 'u': /* release lock of a locked revision */ if (!*a) { unlockcaller=true; break; } lockpt = talloc(struct Lockrev); lockpt->revno = a; lockpt->nextrev = nil; if (rmvlock) rmvlock->nextrev = lockpt; else rmvlocklst = lockpt; rmvlock = lockpt; curlock = rmnewlocklst(lockpt); break; case 'L': /* set strict locking */ if (strict_selected++) { /* Already selected L or U? */ if (!strictlock) /* Already selected -U? */ warn("-L overrides -U."); } strictlock = true; break; case 'U': /* release strict locking */ if (strict_selected++) { /* Already selected L or U? */ if (strictlock) /* Already selected -L? */ warn("-L overrides -U."); } else strictlock = false; break; case 'n': /* add new association: error, if name exists */ if (!*a) { error("missing symbolic name after -n"); break; } getassoclst(false, (*argv)+1); break; case 'N': /* add or change association */ if (!*a) { error("missing symbolic name after -N"); break; } getassoclst(true, (*argv)+1); break; case 'm': /* change log message */ getmessage(a); break; case 'o': /* delete revisions */ if (delrev.strt) redefined('o'); if (!*a) { error("missing revision range after -o"); break; } getdelrev( (*argv)+1 ); break; case 's': /* change state attribute of a revision */ if (!*a) { error("state missing after -s"); break; } getstates( (*argv)+1); break; case 't': /* change descriptive text */ textflag=true; if (*a) { if (textfile) redefined('t'); textfile = a; } break; case 'I': interactiveflag = true; break; case 'q': quietflag = true; break; case 'x': suffixes = a; break; case 'V': setRCSversion(*argv); break; case 'k': /* set keyword expand mode */ if (0 <= expmode) redefined('k'); if (0 <= (expmode = str2expmode(a))) break; /* fall into */ default: faterror("unknown option: %s%s", *argv, cmdusage); }; } /* end processing of options */ if (argc<1) faterror("no input file%s", cmdusage); if (nerror) { diagnose("%s aborted\n",cmdid); exitmain(EXIT_FAILURE); } if (initflag) { defaultRCSmode = umask((mode_t)0); VOID umask(defaultRCSmode); defaultRCSmode = (S_IRUSR|S_IRGRP|S_IROTH) & ~defaultRCSmode; } /* now handle all filenames */ do { ffree(); if ( initflag ) { switch (pairfilenames(argc, argv, rcswriteopen, false, false)) { case -1: break; /* not exist; ok */ case 0: continue; /* error */ case 1: error("file %s exists already", RCSfilename); continue; } } else { switch (pairfilenames(argc, argv, rcswriteopen, true, false)) { case -1: continue; /* not exist */ case 0: continue; /* errors */ case 1: break; /* file exists; ok*/ } } /* now RCSfilename contains the name of the RCS file, and * workfilename contains the name of the working file. * if !initflag, finptr contains the file descriptor for the * RCS file. The admin node is initialized. */ diagnose("RCS file: %s\n", RCSfilename); RCSmode = defaultRCSmode; if (initflag) { if (stat(workfilename, &workstat) == 0) RCSmode = workstat.st_mode; } else { if (!checkaccesslist()) continue; gettree(); /* Read the delta tree. */ RCSmode = RCSstat.st_mode; } RCSmode &= ~(S_IWUSR|S_IWGRP|S_IWOTH); /* update admin. node */ if (strict_selected) StrictLocks = strictlock; if (commsyml) { Comment.string = commsyml; Comment.size = strlen(commsyml); } if (0 <= expmode) Expand = expmode; /* update default branch */ if (branchflag && expandsym(branchsym, &branchnum)) { if (countnumflds(branchnum.string)) { Dbranch = branchnum.string; } else Dbranch = nil; } doaccess(); /* Update access list. */ doassoc(); /* Update association list. */ dolocks(); /* Update locks. */ domessages(); /* Update log messages. */ /* update state attribution */ if (chgheadstate) { /* change state of default branch or head */ if (Dbranch==nil) { if (Head==nil) warn("can't change states in an empty tree"); else Head->state = headstate; } else { rcs_setstate(Dbranch,headstate); /* Can't set directly */ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -