1*86d7f5d3SJohn Marino /* Change RCS file attributes. */
2*86d7f5d3SJohn Marino
3*86d7f5d3SJohn Marino /* Copyright 1982, 1988, 1989 Walter Tichy
4*86d7f5d3SJohn Marino Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
5*86d7f5d3SJohn Marino Distributed under license by the Free Software Foundation, Inc.
6*86d7f5d3SJohn Marino
7*86d7f5d3SJohn Marino This file is part of RCS.
8*86d7f5d3SJohn Marino
9*86d7f5d3SJohn Marino RCS is free software; you can redistribute it and/or modify
10*86d7f5d3SJohn Marino it under the terms of the GNU General Public License as published by
11*86d7f5d3SJohn Marino the Free Software Foundation; either version 2, or (at your option)
12*86d7f5d3SJohn Marino any later version.
13*86d7f5d3SJohn Marino
14*86d7f5d3SJohn Marino RCS is distributed in the hope that it will be useful,
15*86d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
16*86d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17*86d7f5d3SJohn Marino GNU General Public License for more details.
18*86d7f5d3SJohn Marino
19*86d7f5d3SJohn Marino You should have received a copy of the GNU General Public License
20*86d7f5d3SJohn Marino along with RCS; see the file COPYING.
21*86d7f5d3SJohn Marino If not, write to the Free Software Foundation,
22*86d7f5d3SJohn Marino 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23*86d7f5d3SJohn Marino
24*86d7f5d3SJohn Marino Report problems and direct all questions to:
25*86d7f5d3SJohn Marino
26*86d7f5d3SJohn Marino rcs-bugs@cs.purdue.edu
27*86d7f5d3SJohn Marino
28*86d7f5d3SJohn Marino */
29*86d7f5d3SJohn Marino
30*86d7f5d3SJohn Marino /*
31*86d7f5d3SJohn Marino * $FreeBSD: src/gnu/usr.bin/rcs/rcs/rcs.c,v 1.7 1999/08/27 23:36:52 peter Exp $
32*86d7f5d3SJohn Marino * $DragonFly: src/gnu/usr.bin/rcs/rcs/rcs.c,v 1.2 2003/06/17 04:25:47 dillon Exp $
33*86d7f5d3SJohn Marino *
34*86d7f5d3SJohn Marino * Revision 5.21 1995/06/16 06:19:24 eggert
35*86d7f5d3SJohn Marino * Update FSF address.
36*86d7f5d3SJohn Marino *
37*86d7f5d3SJohn Marino * Revision 5.20 1995/06/01 16:23:43 eggert
38*86d7f5d3SJohn Marino * (main): Warn if no options were given. Punctuate messages properly.
39*86d7f5d3SJohn Marino *
40*86d7f5d3SJohn Marino * (sendmail): Rewind mailmess before flushing it.
41*86d7f5d3SJohn Marino * Output another warning if mail should work but fails.
42*86d7f5d3SJohn Marino *
43*86d7f5d3SJohn Marino * (buildeltatext): Pass "--binary" if -kb and if --binary makes a difference.
44*86d7f5d3SJohn Marino *
45*86d7f5d3SJohn Marino * Revision 5.19 1994/03/17 14:05:48 eggert
46*86d7f5d3SJohn Marino * Use ORCSerror to clean up after a fatal error. Remove lint.
47*86d7f5d3SJohn Marino * Specify subprocess input via file descriptor, not file name. Remove lint.
48*86d7f5d3SJohn Marino * Flush stderr after prompt.
49*86d7f5d3SJohn Marino *
50*86d7f5d3SJohn Marino * Revision 5.18 1993/11/09 17:40:15 eggert
51*86d7f5d3SJohn Marino * -V now prints version on stdout and exits. Don't print usage twice.
52*86d7f5d3SJohn Marino *
53*86d7f5d3SJohn Marino * Revision 5.17 1993/11/03 17:42:27 eggert
54*86d7f5d3SJohn Marino * Add -z. Don't lose track of -m or -t when there are no other changes.
55*86d7f5d3SJohn Marino * Don't discard ignored phrases. Improve quality of diagnostics.
56*86d7f5d3SJohn Marino *
57*86d7f5d3SJohn Marino * Revision 5.16 1992/07/28 16:12:44 eggert
58*86d7f5d3SJohn Marino * rcs -l now asks whether you want to break the lock.
59*86d7f5d3SJohn Marino * Add -V. Set RCS file's mode and time at right moment.
60*86d7f5d3SJohn Marino *
61*86d7f5d3SJohn Marino * Revision 5.15 1992/02/17 23:02:20 eggert
62*86d7f5d3SJohn Marino * Add -T.
63*86d7f5d3SJohn Marino *
64*86d7f5d3SJohn Marino * Revision 5.14 1992/01/27 16:42:53 eggert
65*86d7f5d3SJohn Marino * Add -M. Avoid invoking umask(); it's one less thing to configure.
66*86d7f5d3SJohn Marino * Add support for bad_creat0. lint -> RCS_lint
67*86d7f5d3SJohn Marino *
68*86d7f5d3SJohn Marino * Revision 5.13 1992/01/06 02:42:34 eggert
69*86d7f5d3SJohn Marino * Avoid changing RCS file in common cases where no change can occur.
70*86d7f5d3SJohn Marino *
71*86d7f5d3SJohn Marino * Revision 5.12 1991/11/20 17:58:08 eggert
72*86d7f5d3SJohn Marino * Don't read the delta tree from a nonexistent RCS file.
73*86d7f5d3SJohn Marino *
74*86d7f5d3SJohn Marino * Revision 5.11 1991/10/07 17:32:46 eggert
75*86d7f5d3SJohn Marino * Remove lint.
76*86d7f5d3SJohn Marino *
77*86d7f5d3SJohn Marino * Revision 5.10 1991/08/19 23:17:54 eggert
78*86d7f5d3SJohn Marino * Add -m, -r$, piece tables. Revision separator is `:', not `-'. Tune.
79*86d7f5d3SJohn Marino *
80*86d7f5d3SJohn Marino * Revision 5.9 1991/04/21 11:58:18 eggert
81*86d7f5d3SJohn Marino * Add -x, RCSINIT, MS-DOS support.
82*86d7f5d3SJohn Marino *
83*86d7f5d3SJohn Marino * Revision 5.8 1991/02/25 07:12:38 eggert
84*86d7f5d3SJohn Marino * strsave -> str_save (DG/UX name clash)
85*86d7f5d3SJohn Marino * 0444 -> S_IRUSR|S_IRGRP|S_IROTH for portability
86*86d7f5d3SJohn Marino *
87*86d7f5d3SJohn Marino * Revision 5.7 1990/12/18 17:19:21 eggert
88*86d7f5d3SJohn Marino * Fix bug with multiple -n and -N options.
89*86d7f5d3SJohn Marino *
90*86d7f5d3SJohn Marino * Revision 5.6 1990/12/04 05:18:40 eggert
91*86d7f5d3SJohn Marino * Use -I for prompts and -q for diagnostics.
92*86d7f5d3SJohn Marino *
93*86d7f5d3SJohn Marino * Revision 5.5 1990/11/11 00:06:35 eggert
94*86d7f5d3SJohn Marino * Fix `rcs -e' core dump.
95*86d7f5d3SJohn Marino *
96*86d7f5d3SJohn Marino * Revision 5.4 1990/11/01 05:03:33 eggert
97*86d7f5d3SJohn Marino * Add -I and new -t behavior. Permit arbitrary data in logs.
98*86d7f5d3SJohn Marino *
99*86d7f5d3SJohn Marino * Revision 5.3 1990/10/04 06:30:16 eggert
100*86d7f5d3SJohn Marino * Accumulate exit status across files.
101*86d7f5d3SJohn Marino *
102*86d7f5d3SJohn Marino * Revision 5.2 1990/09/04 08:02:17 eggert
103*86d7f5d3SJohn Marino * Standardize yes-or-no procedure.
104*86d7f5d3SJohn Marino *
105*86d7f5d3SJohn Marino * Revision 5.1 1990/08/29 07:13:51 eggert
106*86d7f5d3SJohn Marino * Remove unused setuid support. Clean old log messages too.
107*86d7f5d3SJohn Marino *
108*86d7f5d3SJohn Marino * Revision 5.0 1990/08/22 08:12:42 eggert
109*86d7f5d3SJohn Marino * Don't lose names when applying -a option to multiple files.
110*86d7f5d3SJohn Marino * Remove compile-time limits; use malloc instead. Add setuid support.
111*86d7f5d3SJohn Marino * Permit dates past 1999/12/31. Make lock and temp files faster and safer.
112*86d7f5d3SJohn Marino * Ansify and Posixate. Add -V. Fix umask bug. Make linting easier. Tune.
113*86d7f5d3SJohn Marino * Yield proper exit status. Check diff's output.
114*86d7f5d3SJohn Marino *
115*86d7f5d3SJohn Marino * Revision 4.11 89/05/01 15:12:06 narten
116*86d7f5d3SJohn Marino * changed copyright header to reflect current distribution rules
117*86d7f5d3SJohn Marino *
118*86d7f5d3SJohn Marino * Revision 4.10 88/11/08 16:01:54 narten
119*86d7f5d3SJohn Marino * didn't install previous patch correctly
120*86d7f5d3SJohn Marino *
121*86d7f5d3SJohn Marino * Revision 4.9 88/11/08 13:56:01 narten
122*86d7f5d3SJohn Marino * removed include <sysexits.h> (not needed)
123*86d7f5d3SJohn Marino * minor fix for -A option
124*86d7f5d3SJohn Marino *
125*86d7f5d3SJohn Marino * Revision 4.8 88/08/09 19:12:27 eggert
126*86d7f5d3SJohn Marino * Don't access freed storage.
127*86d7f5d3SJohn Marino * Use execv(), not system(); yield proper exit status; remove lint.
128*86d7f5d3SJohn Marino *
129*86d7f5d3SJohn Marino * Revision 4.7 87/12/18 11:37:17 narten
130*86d7f5d3SJohn Marino * lint cleanups (Guy Harris)
131*86d7f5d3SJohn Marino *
132*86d7f5d3SJohn Marino * Revision 4.6 87/10/18 10:28:48 narten
133*86d7f5d3SJohn Marino * Updating verison numbers. Changes relative to 1.1 are actually
134*86d7f5d3SJohn Marino * relative to 4.3
135*86d7f5d3SJohn Marino *
136*86d7f5d3SJohn Marino * Revision 1.4 87/09/24 13:58:52 narten
137*86d7f5d3SJohn Marino * Sources now pass through lint (if you ignore printf/sprintf/fprintf
138*86d7f5d3SJohn Marino * warnings)
139*86d7f5d3SJohn Marino *
140*86d7f5d3SJohn Marino * Revision 1.3 87/03/27 14:21:55 jenkins
141*86d7f5d3SJohn Marino * Port to suns
142*86d7f5d3SJohn Marino *
143*86d7f5d3SJohn Marino * Revision 1.2 85/12/17 13:59:09 albitz
144*86d7f5d3SJohn Marino * Changed setstate to rcs_setstate because of conflict with random.o.
145*86d7f5d3SJohn Marino *
146*86d7f5d3SJohn Marino * Revision 4.3 83/12/15 12:27:33 wft
147*86d7f5d3SJohn Marino * rcs -u now breaks most recent lock if it can't find a lock by the caller.
148*86d7f5d3SJohn Marino *
149*86d7f5d3SJohn Marino * Revision 4.2 83/12/05 10:18:20 wft
150*86d7f5d3SJohn Marino * Added conditional compilation for sending mail.
151*86d7f5d3SJohn Marino * Alternatives: V4_2BSD, V6, USG, and other.
152*86d7f5d3SJohn Marino *
153*86d7f5d3SJohn Marino * Revision 4.1 83/05/10 16:43:02 wft
154*86d7f5d3SJohn Marino * Simplified breaklock(); added calls to findlock() and getcaller().
155*86d7f5d3SJohn Marino * Added option -b (default branch). Updated -s and -w for -b.
156*86d7f5d3SJohn Marino * Removed calls to stat(); now done by pairfilenames().
157*86d7f5d3SJohn Marino * Replaced most catchints() calls with restoreints().
158*86d7f5d3SJohn Marino * Removed check for exit status of delivermail().
159*86d7f5d3SJohn Marino * Directed all interactive output to stderr.
160*86d7f5d3SJohn Marino *
161*86d7f5d3SJohn Marino * Revision 3.9.1.1 83/12/02 22:08:51 wft
162*86d7f5d3SJohn Marino * Added conditional compilation for 4.2 sendmail and 4.1 delivermail.
163*86d7f5d3SJohn Marino *
164*86d7f5d3SJohn Marino * Revision 3.9 83/02/15 15:38:39 wft
165*86d7f5d3SJohn Marino * Added call to fastcopy() to copy remainder of RCS file.
166*86d7f5d3SJohn Marino *
167*86d7f5d3SJohn Marino * Revision 3.8 83/01/18 17:37:51 wft
168*86d7f5d3SJohn Marino * Changed sendmail(): now uses delivermail, and asks whether to break the lock.
169*86d7f5d3SJohn Marino *
170*86d7f5d3SJohn Marino * Revision 3.7 83/01/15 18:04:25 wft
171*86d7f5d3SJohn Marino * Removed putree(); replaced with puttree() in rcssyn.c.
172*86d7f5d3SJohn Marino * Combined putdellog() and scanlogtext(); deleted putdellog().
173*86d7f5d3SJohn Marino * Cleaned up diagnostics and error messages. Fixed problem with
174*86d7f5d3SJohn Marino * mutilated files in case of deletions in 2 files in a single command.
175*86d7f5d3SJohn Marino * Changed marking of selector from 'D' to DELETE.
176*86d7f5d3SJohn Marino *
177*86d7f5d3SJohn Marino * Revision 3.6 83/01/14 15:37:31 wft
178*86d7f5d3SJohn Marino * Added ignoring of interrupts while new RCS file is renamed;
179*86d7f5d3SJohn Marino * Avoids deletion of RCS files by interrupts.
180*86d7f5d3SJohn Marino *
181*86d7f5d3SJohn Marino * Revision 3.5 82/12/10 21:11:39 wft
182*86d7f5d3SJohn Marino * Removed unused variables, fixed checking of return code from diff,
183*86d7f5d3SJohn Marino * introduced variant COMPAT2 for skipping Suffix on -A files.
184*86d7f5d3SJohn Marino *
185*86d7f5d3SJohn Marino * Revision 3.4 82/12/04 13:18:20 wft
186*86d7f5d3SJohn Marino * Replaced getdelta() with gettree(), changed breaklock to update
187*86d7f5d3SJohn Marino * field lockedby, added some diagnostics.
188*86d7f5d3SJohn Marino *
189*86d7f5d3SJohn Marino * Revision 3.3 82/12/03 17:08:04 wft
190*86d7f5d3SJohn Marino * Replaced getlogin() with getpwuid(), flcose() with ffclose(),
191*86d7f5d3SJohn Marino * /usr/ucb/Mail with macro MAIL. Removed handling of Suffix (-x).
192*86d7f5d3SJohn Marino * fixed -u for missing revno. Disambiguated structure members.
193*86d7f5d3SJohn Marino *
194*86d7f5d3SJohn Marino * Revision 3.2 82/10/18 21:05:07 wft
195*86d7f5d3SJohn Marino * rcs -i now generates a file mode given by the umask minus write permission;
196*86d7f5d3SJohn Marino * otherwise, rcs keeps the mode, but removes write permission.
197*86d7f5d3SJohn Marino * I added a check for write error, fixed call to getlogin(), replaced
198*86d7f5d3SJohn Marino * curdir() with getfullRCSname(), cleaned up handling -U/L, and changed
199*86d7f5d3SJohn Marino * conflicting, long identifiers.
200*86d7f5d3SJohn Marino *
201*86d7f5d3SJohn Marino * Revision 3.1 82/10/13 16:11:07 wft
202*86d7f5d3SJohn Marino * fixed type of variables receiving from getc() (char -> int).
203*86d7f5d3SJohn Marino */
204*86d7f5d3SJohn Marino
205*86d7f5d3SJohn Marino
206*86d7f5d3SJohn Marino #include "rcsbase.h"
207*86d7f5d3SJohn Marino
208*86d7f5d3SJohn Marino struct Lockrev {
209*86d7f5d3SJohn Marino char const *revno;
210*86d7f5d3SJohn Marino struct Lockrev * nextrev;
211*86d7f5d3SJohn Marino };
212*86d7f5d3SJohn Marino
213*86d7f5d3SJohn Marino struct Symrev {
214*86d7f5d3SJohn Marino char const *revno;
215*86d7f5d3SJohn Marino char const *ssymbol;
216*86d7f5d3SJohn Marino int override;
217*86d7f5d3SJohn Marino struct Symrev * nextsym;
218*86d7f5d3SJohn Marino };
219*86d7f5d3SJohn Marino
220*86d7f5d3SJohn Marino struct Message {
221*86d7f5d3SJohn Marino char const *revno;
222*86d7f5d3SJohn Marino struct cbuf message;
223*86d7f5d3SJohn Marino struct Message *nextmessage;
224*86d7f5d3SJohn Marino };
225*86d7f5d3SJohn Marino
226*86d7f5d3SJohn Marino struct Status {
227*86d7f5d3SJohn Marino char const *revno;
228*86d7f5d3SJohn Marino char const *status;
229*86d7f5d3SJohn Marino struct Status * nextstatus;
230*86d7f5d3SJohn Marino };
231*86d7f5d3SJohn Marino
232*86d7f5d3SJohn Marino enum changeaccess {append, erase};
233*86d7f5d3SJohn Marino struct chaccess {
234*86d7f5d3SJohn Marino char const *login;
235*86d7f5d3SJohn Marino enum changeaccess command;
236*86d7f5d3SJohn Marino struct chaccess *nextchaccess;
237*86d7f5d3SJohn Marino };
238*86d7f5d3SJohn Marino
239*86d7f5d3SJohn Marino struct delrevpair {
240*86d7f5d3SJohn Marino char const *strt;
241*86d7f5d3SJohn Marino char const *end;
242*86d7f5d3SJohn Marino int code;
243*86d7f5d3SJohn Marino };
244*86d7f5d3SJohn Marino
245*86d7f5d3SJohn Marino static int branchpoint P((struct hshentry*,struct hshentry*));
246*86d7f5d3SJohn Marino static int breaklock P((struct hshentry const*));
247*86d7f5d3SJohn Marino static int buildeltatext P((struct hshentries const*));
248*86d7f5d3SJohn Marino static int doaccess P((void));
249*86d7f5d3SJohn Marino static int doassoc P((void));
250*86d7f5d3SJohn Marino static int dolocks P((void));
251*86d7f5d3SJohn Marino static int domessages P((void));
252*86d7f5d3SJohn Marino static int rcs_setstate P((char const*,char const*));
253*86d7f5d3SJohn Marino static int removerevs P((void));
254*86d7f5d3SJohn Marino static int sendmail P((char const*,char const*));
255*86d7f5d3SJohn Marino static int setlock P((char const*));
256*86d7f5d3SJohn Marino static struct Lockrev **rmnewlocklst P((char const*));
257*86d7f5d3SJohn Marino static struct hshentry *searchcutpt P((char const*,int,struct hshentries*));
258*86d7f5d3SJohn Marino static void buildtree P((void));
259*86d7f5d3SJohn Marino static void cleanup P((void));
260*86d7f5d3SJohn Marino static void getaccessor P((char*,enum changeaccess));
261*86d7f5d3SJohn Marino static void getassoclst P((int,char*));
262*86d7f5d3SJohn Marino static void getchaccess P((char const*,enum changeaccess));
263*86d7f5d3SJohn Marino static void getdelrev P((char*));
264*86d7f5d3SJohn Marino static void getmessage P((char*));
265*86d7f5d3SJohn Marino static void getstates P((char*));
266*86d7f5d3SJohn Marino static void scanlogtext P((struct hshentry*,int));
267*86d7f5d3SJohn Marino
268*86d7f5d3SJohn Marino static struct buf numrev;
269*86d7f5d3SJohn Marino static char const *headstate;
270*86d7f5d3SJohn Marino static int chgheadstate, exitstatus, lockhead, unlockcaller;
271*86d7f5d3SJohn Marino static int suppress_mail;
272*86d7f5d3SJohn Marino static struct Lockrev *newlocklst, *rmvlocklst;
273*86d7f5d3SJohn Marino static struct Message *messagelst, **nextmessage;
274*86d7f5d3SJohn Marino static struct Status *statelst, **nextstate;
275*86d7f5d3SJohn Marino static struct Symrev *assoclst, **nextassoc;
276*86d7f5d3SJohn Marino static struct chaccess *chaccess, **nextchaccess;
277*86d7f5d3SJohn Marino static struct delrevpair delrev;
278*86d7f5d3SJohn Marino static struct hshentry *cuthead, *cuttail, *delstrt;
279*86d7f5d3SJohn Marino static struct hshentries *gendeltas;
280*86d7f5d3SJohn Marino
281*86d7f5d3SJohn Marino mainProg(rcsId, "rcs", "$DragonFly: src/gnu/usr.bin/rcs/rcs/rcs.c,v 1.2 2003/06/17 04:25:47 dillon Exp $")
282*86d7f5d3SJohn Marino {
283*86d7f5d3SJohn Marino static char const cmdusage[] =
284*86d7f5d3SJohn Marino "\nrcs usage: rcs -{ae}logins -Afile -{blu}[rev] -cstring -{iILqTU} -ksubst -mrev:msg -{nN}name[:[rev]] -orange -sstate[:rev] -t[text] -Vn -xsuff -zzone file ...";
285*86d7f5d3SJohn Marino
286*86d7f5d3SJohn Marino char *a, **newargv, *textfile;
287*86d7f5d3SJohn Marino char const *branchsym, *commsyml;
288*86d7f5d3SJohn Marino int branchflag, changed, expmode, initflag;
289*86d7f5d3SJohn Marino int strictlock, strict_selected, textflag;
290*86d7f5d3SJohn Marino int keepRCStime, Ttimeflag;
291*86d7f5d3SJohn Marino size_t commsymlen;
292*86d7f5d3SJohn Marino struct buf branchnum;
293*86d7f5d3SJohn Marino struct Lockrev *lockpt;
294*86d7f5d3SJohn Marino struct Lockrev **curlock, **rmvlock;
295*86d7f5d3SJohn Marino struct Status * curstate;
296*86d7f5d3SJohn Marino
297*86d7f5d3SJohn Marino nosetid();
298*86d7f5d3SJohn Marino
299*86d7f5d3SJohn Marino nextassoc = &assoclst;
300*86d7f5d3SJohn Marino nextchaccess = &chaccess;
301*86d7f5d3SJohn Marino nextmessage = &messagelst;
302*86d7f5d3SJohn Marino nextstate = &statelst;
303*86d7f5d3SJohn Marino branchsym = commsyml = textfile = 0;
304*86d7f5d3SJohn Marino branchflag = strictlock = false;
305*86d7f5d3SJohn Marino bufautobegin(&branchnum);
306*86d7f5d3SJohn Marino commsymlen = 0;
307*86d7f5d3SJohn Marino curlock = &newlocklst;
308*86d7f5d3SJohn Marino rmvlock = &rmvlocklst;
309*86d7f5d3SJohn Marino expmode = -1;
310*86d7f5d3SJohn Marino suffixes = X_DEFAULT;
311*86d7f5d3SJohn Marino initflag= textflag = false;
312*86d7f5d3SJohn Marino strict_selected = 0;
313*86d7f5d3SJohn Marino Ttimeflag = false;
314*86d7f5d3SJohn Marino
315*86d7f5d3SJohn Marino /* preprocessing command options */
316*86d7f5d3SJohn Marino if (1 < argc && argv[1][0] != '-')
317*86d7f5d3SJohn Marino warn("No options were given; this usage is obsolescent.");
318*86d7f5d3SJohn Marino
319*86d7f5d3SJohn Marino argc = getRCSINIT(argc, argv, &newargv);
320*86d7f5d3SJohn Marino argv = newargv;
321*86d7f5d3SJohn Marino while (a = *++argv, 0<--argc && *a++=='-') {
322*86d7f5d3SJohn Marino switch (*a++) {
323*86d7f5d3SJohn Marino
324*86d7f5d3SJohn Marino case 'i': /* initial version */
325*86d7f5d3SJohn Marino initflag = true;
326*86d7f5d3SJohn Marino break;
327*86d7f5d3SJohn Marino
328*86d7f5d3SJohn Marino case 'b': /* change default branch */
329*86d7f5d3SJohn Marino if (branchflag) redefined('b');
330*86d7f5d3SJohn Marino branchflag= true;
331*86d7f5d3SJohn Marino branchsym = a;
332*86d7f5d3SJohn Marino break;
333*86d7f5d3SJohn Marino
334*86d7f5d3SJohn Marino case 'c': /* change comment symbol */
335*86d7f5d3SJohn Marino if (commsyml) redefined('c');
336*86d7f5d3SJohn Marino commsyml = a;
337*86d7f5d3SJohn Marino commsymlen = strlen(a);
338*86d7f5d3SJohn Marino break;
339*86d7f5d3SJohn Marino
340*86d7f5d3SJohn Marino case 'a': /* add new accessor */
341*86d7f5d3SJohn Marino getaccessor(*argv+1, append);
342*86d7f5d3SJohn Marino break;
343*86d7f5d3SJohn Marino
344*86d7f5d3SJohn Marino case 'A': /* append access list according to accessfile */
345*86d7f5d3SJohn Marino if (!*a) {
346*86d7f5d3SJohn Marino error("missing pathname after -A");
347*86d7f5d3SJohn Marino break;
348*86d7f5d3SJohn Marino }
349*86d7f5d3SJohn Marino *argv = a;
350*86d7f5d3SJohn Marino if (0 < pairnames(1,argv,rcsreadopen,true,false)) {
351*86d7f5d3SJohn Marino while (AccessList) {
352*86d7f5d3SJohn Marino getchaccess(str_save(AccessList->login),append);
353*86d7f5d3SJohn Marino AccessList = AccessList->nextaccess;
354*86d7f5d3SJohn Marino }
355*86d7f5d3SJohn Marino Izclose(&finptr);
356*86d7f5d3SJohn Marino }
357*86d7f5d3SJohn Marino break;
358*86d7f5d3SJohn Marino
359*86d7f5d3SJohn Marino case 'e': /* remove accessors */
360*86d7f5d3SJohn Marino getaccessor(*argv+1, erase);
361*86d7f5d3SJohn Marino break;
362*86d7f5d3SJohn Marino
363*86d7f5d3SJohn Marino case 'l': /* lock a revision if it is unlocked */
364*86d7f5d3SJohn Marino if (!*a) {
365*86d7f5d3SJohn Marino /* Lock head or default branch. */
366*86d7f5d3SJohn Marino lockhead = true;
367*86d7f5d3SJohn Marino break;
368*86d7f5d3SJohn Marino }
369*86d7f5d3SJohn Marino *curlock = lockpt = talloc(struct Lockrev);
370*86d7f5d3SJohn Marino lockpt->revno = a;
371*86d7f5d3SJohn Marino lockpt->nextrev = 0;
372*86d7f5d3SJohn Marino curlock = &lockpt->nextrev;
373*86d7f5d3SJohn Marino break;
374*86d7f5d3SJohn Marino
375*86d7f5d3SJohn Marino case 'u': /* release lock of a locked revision */
376*86d7f5d3SJohn Marino if (!*a) {
377*86d7f5d3SJohn Marino unlockcaller=true;
378*86d7f5d3SJohn Marino break;
379*86d7f5d3SJohn Marino }
380*86d7f5d3SJohn Marino *rmvlock = lockpt = talloc(struct Lockrev);
381*86d7f5d3SJohn Marino lockpt->revno = a;
382*86d7f5d3SJohn Marino lockpt->nextrev = 0;
383*86d7f5d3SJohn Marino rmvlock = &lockpt->nextrev;
384*86d7f5d3SJohn Marino curlock = rmnewlocklst(lockpt->revno);
385*86d7f5d3SJohn Marino break;
386*86d7f5d3SJohn Marino
387*86d7f5d3SJohn Marino case 'L': /* set strict locking */
388*86d7f5d3SJohn Marino if (strict_selected) {
389*86d7f5d3SJohn Marino if (!strictlock) /* Already selected -U? */
390*86d7f5d3SJohn Marino warn("-U overridden by -L");
391*86d7f5d3SJohn Marino }
392*86d7f5d3SJohn Marino strictlock = true;
393*86d7f5d3SJohn Marino strict_selected = true;
394*86d7f5d3SJohn Marino break;
395*86d7f5d3SJohn Marino
396*86d7f5d3SJohn Marino case 'U': /* release strict locking */
397*86d7f5d3SJohn Marino if (strict_selected) {
398*86d7f5d3SJohn Marino if (strictlock) /* Already selected -L? */
399*86d7f5d3SJohn Marino warn("-L overridden by -U");
400*86d7f5d3SJohn Marino }
401*86d7f5d3SJohn Marino strict_selected = true;
402*86d7f5d3SJohn Marino break;
403*86d7f5d3SJohn Marino
404*86d7f5d3SJohn Marino case 'n': /* add new association: error, if name exists */
405*86d7f5d3SJohn Marino if (!*a) {
406*86d7f5d3SJohn Marino error("missing symbolic name after -n");
407*86d7f5d3SJohn Marino break;
408*86d7f5d3SJohn Marino }
409*86d7f5d3SJohn Marino getassoclst(false, (*argv)+1);
410*86d7f5d3SJohn Marino break;
411*86d7f5d3SJohn Marino
412*86d7f5d3SJohn Marino case 'N': /* add or change association */
413*86d7f5d3SJohn Marino if (!*a) {
414*86d7f5d3SJohn Marino error("missing symbolic name after -N");
415*86d7f5d3SJohn Marino break;
416*86d7f5d3SJohn Marino }
417*86d7f5d3SJohn Marino getassoclst(true, (*argv)+1);
418*86d7f5d3SJohn Marino break;
419*86d7f5d3SJohn Marino
420*86d7f5d3SJohn Marino case 'm': /* change log message */
421*86d7f5d3SJohn Marino getmessage(a);
422*86d7f5d3SJohn Marino break;
423*86d7f5d3SJohn Marino
424*86d7f5d3SJohn Marino case 'M': /* do not send mail */
425*86d7f5d3SJohn Marino suppress_mail = true;
426*86d7f5d3SJohn Marino break;
427*86d7f5d3SJohn Marino
428*86d7f5d3SJohn Marino case 'o': /* delete revisions */
429*86d7f5d3SJohn Marino if (delrev.strt) redefined('o');
430*86d7f5d3SJohn Marino if (!*a) {
431*86d7f5d3SJohn Marino error("missing revision range after -o");
432*86d7f5d3SJohn Marino break;
433*86d7f5d3SJohn Marino }
434*86d7f5d3SJohn Marino getdelrev( (*argv)+1 );
435*86d7f5d3SJohn Marino break;
436*86d7f5d3SJohn Marino
437*86d7f5d3SJohn Marino case 's': /* change state attribute of a revision */
438*86d7f5d3SJohn Marino if (!*a) {
439*86d7f5d3SJohn Marino error("state missing after -s");
440*86d7f5d3SJohn Marino break;
441*86d7f5d3SJohn Marino }
442*86d7f5d3SJohn Marino getstates( (*argv)+1);
443*86d7f5d3SJohn Marino break;
444*86d7f5d3SJohn Marino
445*86d7f5d3SJohn Marino case 't': /* change descriptive text */
446*86d7f5d3SJohn Marino textflag=true;
447*86d7f5d3SJohn Marino if (*a) {
448*86d7f5d3SJohn Marino if (textfile) redefined('t');
449*86d7f5d3SJohn Marino textfile = a;
450*86d7f5d3SJohn Marino }
451*86d7f5d3SJohn Marino break;
452*86d7f5d3SJohn Marino
453*86d7f5d3SJohn Marino case 'T': /* do not update last-mod time for minor changes */
454*86d7f5d3SJohn Marino if (*a)
455*86d7f5d3SJohn Marino goto unknown;
456*86d7f5d3SJohn Marino Ttimeflag = true;
457*86d7f5d3SJohn Marino break;
458*86d7f5d3SJohn Marino
459*86d7f5d3SJohn Marino case 'I':
460*86d7f5d3SJohn Marino interactiveflag = true;
461*86d7f5d3SJohn Marino break;
462*86d7f5d3SJohn Marino
463*86d7f5d3SJohn Marino case 'q':
464*86d7f5d3SJohn Marino quietflag = true;
465*86d7f5d3SJohn Marino break;
466*86d7f5d3SJohn Marino
467*86d7f5d3SJohn Marino case 'x':
468*86d7f5d3SJohn Marino suffixes = a;
469*86d7f5d3SJohn Marino break;
470*86d7f5d3SJohn Marino
471*86d7f5d3SJohn Marino case 'V':
472*86d7f5d3SJohn Marino setRCSversion(*argv);
473*86d7f5d3SJohn Marino break;
474*86d7f5d3SJohn Marino
475*86d7f5d3SJohn Marino case 'z':
476*86d7f5d3SJohn Marino zone_set(a);
477*86d7f5d3SJohn Marino break;
478*86d7f5d3SJohn Marino
479*86d7f5d3SJohn Marino case 'k': /* set keyword expand mode */
480*86d7f5d3SJohn Marino if (0 <= expmode) redefined('k');
481*86d7f5d3SJohn Marino if (0 <= (expmode = str2expmode(a)))
482*86d7f5d3SJohn Marino break;
483*86d7f5d3SJohn Marino /* fall into */
484*86d7f5d3SJohn Marino default:
485*86d7f5d3SJohn Marino unknown:
486*86d7f5d3SJohn Marino error("unknown option: %s%s", *argv, cmdusage);
487*86d7f5d3SJohn Marino };
488*86d7f5d3SJohn Marino } /* end processing of options */
489*86d7f5d3SJohn Marino
490*86d7f5d3SJohn Marino /* Now handle all pathnames. */
491*86d7f5d3SJohn Marino if (nerror) cleanup();
492*86d7f5d3SJohn Marino else if (argc < 1) faterror("no input file%s", cmdusage);
493*86d7f5d3SJohn Marino else for (; 0 < argc; cleanup(), ++argv, --argc) {
494*86d7f5d3SJohn Marino
495*86d7f5d3SJohn Marino ffree();
496*86d7f5d3SJohn Marino
497*86d7f5d3SJohn Marino if ( initflag ) {
498*86d7f5d3SJohn Marino switch (pairnames(argc, argv, rcswriteopen, false, false)) {
499*86d7f5d3SJohn Marino case -1: break; /* not exist; ok */
500*86d7f5d3SJohn Marino case 0: continue; /* error */
501*86d7f5d3SJohn Marino case 1: rcserror("already exists");
502*86d7f5d3SJohn Marino continue;
503*86d7f5d3SJohn Marino }
504*86d7f5d3SJohn Marino }
505*86d7f5d3SJohn Marino else {
506*86d7f5d3SJohn Marino switch (pairnames(argc, argv, rcswriteopen, true, false)) {
507*86d7f5d3SJohn Marino case -1: continue; /* not exist */
508*86d7f5d3SJohn Marino case 0: continue; /* errors */
509*86d7f5d3SJohn Marino case 1: break; /* file exists; ok*/
510*86d7f5d3SJohn Marino }
511*86d7f5d3SJohn Marino }
512*86d7f5d3SJohn Marino
513*86d7f5d3SJohn Marino
514*86d7f5d3SJohn Marino /*
515*86d7f5d3SJohn Marino * RCSname contains the name of the RCS file, and
516*86d7f5d3SJohn Marino * workname contains the name of the working file.
517*86d7f5d3SJohn Marino * if !initflag, finptr contains the file descriptor for the
518*86d7f5d3SJohn Marino * RCS file. The admin node is initialized.
519*86d7f5d3SJohn Marino */
520*86d7f5d3SJohn Marino
521*86d7f5d3SJohn Marino diagnose("RCS file: %s\n", RCSname);
522*86d7f5d3SJohn Marino
523*86d7f5d3SJohn Marino changed = initflag | textflag;
524*86d7f5d3SJohn Marino keepRCStime = Ttimeflag;
525*86d7f5d3SJohn Marino if (!initflag) {
526*86d7f5d3SJohn Marino if (!checkaccesslist()) continue;
527*86d7f5d3SJohn Marino gettree(); /* Read the delta tree. */
528*86d7f5d3SJohn Marino }
529*86d7f5d3SJohn Marino
530*86d7f5d3SJohn Marino /* update admin. node */
531*86d7f5d3SJohn Marino if (strict_selected) {
532*86d7f5d3SJohn Marino changed |= StrictLocks ^ strictlock;
533*86d7f5d3SJohn Marino StrictLocks = strictlock;
534*86d7f5d3SJohn Marino }
535*86d7f5d3SJohn Marino if (
536*86d7f5d3SJohn Marino commsyml &&
537*86d7f5d3SJohn Marino (
538*86d7f5d3SJohn Marino commsymlen != Comment.size ||
539*86d7f5d3SJohn Marino memcmp(commsyml, Comment.string, commsymlen) != 0
540*86d7f5d3SJohn Marino )
541*86d7f5d3SJohn Marino ) {
542*86d7f5d3SJohn Marino Comment.string = commsyml;
543*86d7f5d3SJohn Marino Comment.size = strlen(commsyml);
544*86d7f5d3SJohn Marino changed = true;
545*86d7f5d3SJohn Marino }
546*86d7f5d3SJohn Marino if (0 <= expmode && Expand != expmode) {
547*86d7f5d3SJohn Marino Expand = expmode;
548*86d7f5d3SJohn Marino changed = true;
549*86d7f5d3SJohn Marino }
550*86d7f5d3SJohn Marino
551*86d7f5d3SJohn Marino /* update default branch */
552*86d7f5d3SJohn Marino if (branchflag && expandsym(branchsym, &branchnum)) {
553*86d7f5d3SJohn Marino if (countnumflds(branchnum.string)) {
554*86d7f5d3SJohn Marino if (cmpnum(Dbranch, branchnum.string) != 0) {
555*86d7f5d3SJohn Marino Dbranch = branchnum.string;
556*86d7f5d3SJohn Marino changed = true;
557*86d7f5d3SJohn Marino }
558*86d7f5d3SJohn Marino } else
559*86d7f5d3SJohn Marino if (Dbranch) {
560*86d7f5d3SJohn Marino Dbranch = 0;
561*86d7f5d3SJohn Marino changed = true;
562*86d7f5d3SJohn Marino }
563*86d7f5d3SJohn Marino }
564*86d7f5d3SJohn Marino
565*86d7f5d3SJohn Marino changed |= doaccess(); /* Update access list. */
566*86d7f5d3SJohn Marino
567*86d7f5d3SJohn Marino changed |= doassoc(); /* Update association list. */
568*86d7f5d3SJohn Marino
569*86d7f5d3SJohn Marino changed |= dolocks(); /* Update locks. */
570*86d7f5d3SJohn Marino
571*86d7f5d3SJohn Marino changed |= domessages(); /* Update log messages. */
572*86d7f5d3SJohn Marino
573*86d7f5d3SJohn Marino /* update state attribution */
574*86d7f5d3SJohn Marino if (chgheadstate) {
575*86d7f5d3SJohn Marino /* change state of default branch or head */
576*86d7f5d3SJohn Marino if (!Dbranch) {
577*86d7f5d3SJohn Marino if (!Head)
578*86d7f5d3SJohn Marino rcswarn("can't change states in an empty tree");
579*86d7f5d3SJohn Marino else if (strcmp(Head->state, headstate) != 0) {
580*86d7f5d3SJohn Marino Head->state = headstate;
581*86d7f5d3SJohn Marino changed = true;
582*86d7f5d3SJohn Marino }
583*86d7f5d3SJohn Marino } else
584*86d7f5d3SJohn Marino changed |= rcs_setstate(Dbranch,headstate);
585*86d7f5d3SJohn Marino }
586*86d7f5d3SJohn Marino for (curstate = statelst; curstate; curstate = curstate->nextstatus)
587*86d7f5d3SJohn Marino changed |= rcs_setstate(curstate->revno,curstate->status);
588*86d7f5d3SJohn Marino
589*86d7f5d3SJohn Marino cuthead = cuttail = 0;
590*86d7f5d3SJohn Marino if (delrev.strt && removerevs()) {
591*86d7f5d3SJohn Marino /* rebuild delta tree if some deltas are deleted */
592*86d7f5d3SJohn Marino if ( cuttail )
593*86d7f5d3SJohn Marino VOID genrevs(
594*86d7f5d3SJohn Marino cuttail->num, (char *)0, (char *)0, (char *)0,
595*86d7f5d3SJohn Marino &gendeltas
596*86d7f5d3SJohn Marino );
597*86d7f5d3SJohn Marino buildtree();
598*86d7f5d3SJohn Marino changed = true;
599*86d7f5d3SJohn Marino keepRCStime = false;
600*86d7f5d3SJohn Marino }
601*86d7f5d3SJohn Marino
602*86d7f5d3SJohn Marino if (nerror)
603*86d7f5d3SJohn Marino continue;
604*86d7f5d3SJohn Marino
605*86d7f5d3SJohn Marino putadmin();
606*86d7f5d3SJohn Marino if ( Head )
607*86d7f5d3SJohn Marino puttree(Head, frewrite);
608*86d7f5d3SJohn Marino putdesc(textflag,textfile);
609*86d7f5d3SJohn Marino
610*86d7f5d3SJohn Marino if ( Head) {
611*86d7f5d3SJohn Marino if (delrev.strt || messagelst) {
612*86d7f5d3SJohn Marino if (!cuttail || buildeltatext(gendeltas)) {
613*86d7f5d3SJohn Marino advise_access(finptr, MADV_SEQUENTIAL);
614*86d7f5d3SJohn Marino scanlogtext((struct hshentry *)0, false);
615*86d7f5d3SJohn Marino /* copy rest of delta text nodes that are not deleted */
616*86d7f5d3SJohn Marino changed = true;
617*86d7f5d3SJohn Marino }
618*86d7f5d3SJohn Marino }
619*86d7f5d3SJohn Marino }
620*86d7f5d3SJohn Marino
621*86d7f5d3SJohn Marino if (initflag) {
622*86d7f5d3SJohn Marino /* Adjust things for donerewrite's sake. */
623*86d7f5d3SJohn Marino if (stat(workname, &RCSstat) != 0) {
624*86d7f5d3SJohn Marino # if bad_creat0
625*86d7f5d3SJohn Marino mode_t m = umask(0);
626*86d7f5d3SJohn Marino (void) umask(m);
627*86d7f5d3SJohn Marino RCSstat.st_mode = (S_IRUSR|S_IRGRP|S_IROTH) & ~m;
628*86d7f5d3SJohn Marino # else
629*86d7f5d3SJohn Marino changed = -1;
630*86d7f5d3SJohn Marino # endif
631*86d7f5d3SJohn Marino }
632*86d7f5d3SJohn Marino RCSstat.st_nlink = 0;
633*86d7f5d3SJohn Marino keepRCStime = false;
634*86d7f5d3SJohn Marino }
635*86d7f5d3SJohn Marino if (donerewrite(changed,
636*86d7f5d3SJohn Marino keepRCStime ? RCSstat.st_mtime : (time_t)-1
637*86d7f5d3SJohn Marino ) != 0)
638*86d7f5d3SJohn Marino break;
639*86d7f5d3SJohn Marino
640*86d7f5d3SJohn Marino diagnose("done\n");
641*86d7f5d3SJohn Marino }
642*86d7f5d3SJohn Marino
643*86d7f5d3SJohn Marino tempunlink();
644*86d7f5d3SJohn Marino exitmain(exitstatus);
645*86d7f5d3SJohn Marino } /* end of main (rcs) */
646*86d7f5d3SJohn Marino
647*86d7f5d3SJohn Marino static void
cleanup()648*86d7f5d3SJohn Marino cleanup()
649*86d7f5d3SJohn Marino {
650*86d7f5d3SJohn Marino if (nerror) exitstatus = EXIT_FAILURE;
651*86d7f5d3SJohn Marino Izclose(&finptr);
652*86d7f5d3SJohn Marino Ozclose(&fcopy);
653*86d7f5d3SJohn Marino ORCSclose();
654*86d7f5d3SJohn Marino dirtempunlink();
655*86d7f5d3SJohn Marino }
656*86d7f5d3SJohn Marino
657*86d7f5d3SJohn Marino void
exiterr()658*86d7f5d3SJohn Marino exiterr()
659*86d7f5d3SJohn Marino {
660*86d7f5d3SJohn Marino ORCSerror();
661*86d7f5d3SJohn Marino dirtempunlink();
662*86d7f5d3SJohn Marino tempunlink();
663*86d7f5d3SJohn Marino _exit(EXIT_FAILURE);
664*86d7f5d3SJohn Marino }
665*86d7f5d3SJohn Marino
666*86d7f5d3SJohn Marino
667*86d7f5d3SJohn Marino static void
getassoclst(flag,sp)668*86d7f5d3SJohn Marino getassoclst(flag, sp)
669*86d7f5d3SJohn Marino int flag;
670*86d7f5d3SJohn Marino char * sp;
671*86d7f5d3SJohn Marino /* Function: associate a symbolic name to a revision or branch, */
672*86d7f5d3SJohn Marino /* and store in assoclst */
673*86d7f5d3SJohn Marino
674*86d7f5d3SJohn Marino {
675*86d7f5d3SJohn Marino struct Symrev * pt;
676*86d7f5d3SJohn Marino char const *temp;
677*86d7f5d3SJohn Marino int c;
678*86d7f5d3SJohn Marino
679*86d7f5d3SJohn Marino while ((c = *++sp) == ' ' || c == '\t' || c =='\n')
680*86d7f5d3SJohn Marino continue;
681*86d7f5d3SJohn Marino temp = sp;
682*86d7f5d3SJohn Marino sp = checksym(sp, ':'); /* check for invalid symbolic name */
683*86d7f5d3SJohn Marino c = *sp; *sp = '\0';
684*86d7f5d3SJohn Marino while( c == ' ' || c == '\t' || c == '\n') c = *++sp;
685*86d7f5d3SJohn Marino
686*86d7f5d3SJohn Marino if ( c != ':' && c != '\0') {
687*86d7f5d3SJohn Marino error("invalid string %s after option -n or -N",sp);
688*86d7f5d3SJohn Marino return;
689*86d7f5d3SJohn Marino }
690*86d7f5d3SJohn Marino
691*86d7f5d3SJohn Marino pt = talloc(struct Symrev);
692*86d7f5d3SJohn Marino pt->ssymbol = temp;
693*86d7f5d3SJohn Marino pt->override = flag;
694*86d7f5d3SJohn Marino if (c == '\0') /* delete symbol */
695*86d7f5d3SJohn Marino pt->revno = 0;
696*86d7f5d3SJohn Marino else {
697*86d7f5d3SJohn Marino while ((c = *++sp) == ' ' || c == '\n' || c == '\t')
698*86d7f5d3SJohn Marino continue;
699*86d7f5d3SJohn Marino pt->revno = sp;
700*86d7f5d3SJohn Marino }
701*86d7f5d3SJohn Marino pt->nextsym = 0;
702*86d7f5d3SJohn Marino *nextassoc = pt;
703*86d7f5d3SJohn Marino nextassoc = &pt->nextsym;
704*86d7f5d3SJohn Marino }
705*86d7f5d3SJohn Marino
706*86d7f5d3SJohn Marino
707*86d7f5d3SJohn Marino static void
getchaccess(login,command)708*86d7f5d3SJohn Marino getchaccess(login, command)
709*86d7f5d3SJohn Marino char const *login;
710*86d7f5d3SJohn Marino enum changeaccess command;
711*86d7f5d3SJohn Marino {
712*86d7f5d3SJohn Marino register struct chaccess *pt;
713*86d7f5d3SJohn Marino
714*86d7f5d3SJohn Marino pt = talloc(struct chaccess);
715*86d7f5d3SJohn Marino pt->login = login;
716*86d7f5d3SJohn Marino pt->command = command;
717*86d7f5d3SJohn Marino pt->nextchaccess = 0;
718*86d7f5d3SJohn Marino *nextchaccess = pt;
719*86d7f5d3SJohn Marino nextchaccess = &pt->nextchaccess;
720*86d7f5d3SJohn Marino }
721*86d7f5d3SJohn Marino
722*86d7f5d3SJohn Marino
723*86d7f5d3SJohn Marino
724*86d7f5d3SJohn Marino static void
getaccessor(opt,command)725*86d7f5d3SJohn Marino getaccessor(opt, command)
726*86d7f5d3SJohn Marino char *opt;
727*86d7f5d3SJohn Marino enum changeaccess command;
728*86d7f5d3SJohn Marino /* Function: get the accessor list of options -e and -a, */
729*86d7f5d3SJohn Marino /* and store in chaccess */
730*86d7f5d3SJohn Marino
731*86d7f5d3SJohn Marino
732*86d7f5d3SJohn Marino {
733*86d7f5d3SJohn Marino register int c;
734*86d7f5d3SJohn Marino register char *sp;
735*86d7f5d3SJohn Marino
736*86d7f5d3SJohn Marino sp = opt;
737*86d7f5d3SJohn Marino while ((c = *++sp) == ' ' || c == '\n' || c == '\t' || c == ',')
738*86d7f5d3SJohn Marino continue;
739*86d7f5d3SJohn Marino if ( c == '\0') {
740*86d7f5d3SJohn Marino if (command == erase && sp-opt == 1) {
741*86d7f5d3SJohn Marino getchaccess((char*)0, command);
742*86d7f5d3SJohn Marino return;
743*86d7f5d3SJohn Marino }
744*86d7f5d3SJohn Marino error("missing login name after option -a or -e");
745*86d7f5d3SJohn Marino return;
746*86d7f5d3SJohn Marino }
747*86d7f5d3SJohn Marino
748*86d7f5d3SJohn Marino while( c != '\0') {
749*86d7f5d3SJohn Marino getchaccess(sp, command);
750*86d7f5d3SJohn Marino sp = checkid(sp,',');
751*86d7f5d3SJohn Marino c = *sp; *sp = '\0';
752*86d7f5d3SJohn Marino while( c == ' ' || c == '\n' || c == '\t'|| c == ',')c =(*++sp);
753*86d7f5d3SJohn Marino }
754*86d7f5d3SJohn Marino }
755*86d7f5d3SJohn Marino
756*86d7f5d3SJohn Marino
757*86d7f5d3SJohn Marino static void
getmessage(option)758*86d7f5d3SJohn Marino getmessage(option)
759*86d7f5d3SJohn Marino char *option;
760*86d7f5d3SJohn Marino {
761*86d7f5d3SJohn Marino struct Message *pt;
762*86d7f5d3SJohn Marino struct cbuf cb;
763*86d7f5d3SJohn Marino char *m;
764*86d7f5d3SJohn Marino
765*86d7f5d3SJohn Marino if (!(m = strchr(option, ':'))) {
766*86d7f5d3SJohn Marino error("-m option lacks revision number");
767*86d7f5d3SJohn Marino return;
768*86d7f5d3SJohn Marino }
769*86d7f5d3SJohn Marino *m++ = 0;
770*86d7f5d3SJohn Marino cb = cleanlogmsg(m, strlen(m));
771*86d7f5d3SJohn Marino if (!cb.size) {
772*86d7f5d3SJohn Marino error("-m option lacks log message");
773*86d7f5d3SJohn Marino return;
774*86d7f5d3SJohn Marino }
775*86d7f5d3SJohn Marino pt = talloc(struct Message);
776*86d7f5d3SJohn Marino pt->revno = option;
777*86d7f5d3SJohn Marino pt->message = cb;
778*86d7f5d3SJohn Marino pt->nextmessage = 0;
779*86d7f5d3SJohn Marino *nextmessage = pt;
780*86d7f5d3SJohn Marino nextmessage = &pt->nextmessage;
781*86d7f5d3SJohn Marino }
782*86d7f5d3SJohn Marino
783*86d7f5d3SJohn Marino
784*86d7f5d3SJohn Marino static void
getstates(sp)785*86d7f5d3SJohn Marino getstates(sp)
786*86d7f5d3SJohn Marino char *sp;
787*86d7f5d3SJohn Marino /* Function: get one state attribute and the corresponding */
788*86d7f5d3SJohn Marino /* revision and store in statelst */
789*86d7f5d3SJohn Marino
790*86d7f5d3SJohn Marino {
791*86d7f5d3SJohn Marino char const *temp;
792*86d7f5d3SJohn Marino struct Status *pt;
793*86d7f5d3SJohn Marino register int c;
794*86d7f5d3SJohn Marino
795*86d7f5d3SJohn Marino while ((c = *++sp) ==' ' || c == '\t' || c == '\n')
796*86d7f5d3SJohn Marino continue;
797*86d7f5d3SJohn Marino temp = sp;
798*86d7f5d3SJohn Marino sp = checkid(sp,':'); /* check for invalid state attribute */
799*86d7f5d3SJohn Marino c = *sp; *sp = '\0';
800*86d7f5d3SJohn Marino while( c == ' ' || c == '\t' || c == '\n' ) c = *++sp;
801*86d7f5d3SJohn Marino
802*86d7f5d3SJohn Marino if ( c == '\0' ) { /* change state of def. branch or Head */
803*86d7f5d3SJohn Marino chgheadstate = true;
804*86d7f5d3SJohn Marino headstate = temp;
805*86d7f5d3SJohn Marino return;
806*86d7f5d3SJohn Marino }
807*86d7f5d3SJohn Marino else if ( c != ':' ) {
808*86d7f5d3SJohn Marino error("missing ':' after state in option -s");
809*86d7f5d3SJohn Marino return;
810*86d7f5d3SJohn Marino }
811*86d7f5d3SJohn Marino
812*86d7f5d3SJohn Marino while ((c = *++sp) == ' ' || c == '\t' || c == '\n')
813*86d7f5d3SJohn Marino continue;
814*86d7f5d3SJohn Marino pt = talloc(struct Status);
815*86d7f5d3SJohn Marino pt->status = temp;
816*86d7f5d3SJohn Marino pt->revno = sp;
817*86d7f5d3SJohn Marino pt->nextstatus = 0;
818*86d7f5d3SJohn Marino *nextstate = pt;
819*86d7f5d3SJohn Marino nextstate = &pt->nextstatus;
820*86d7f5d3SJohn Marino }
821*86d7f5d3SJohn Marino
822*86d7f5d3SJohn Marino
823*86d7f5d3SJohn Marino
824*86d7f5d3SJohn Marino static void
getdelrev(sp)825*86d7f5d3SJohn Marino getdelrev(sp)
826*86d7f5d3SJohn Marino char *sp;
827*86d7f5d3SJohn Marino /* Function: get revision range or branch to be deleted, */
828*86d7f5d3SJohn Marino /* and place in delrev */
829*86d7f5d3SJohn Marino {
830*86d7f5d3SJohn Marino int c;
831*86d7f5d3SJohn Marino struct delrevpair *pt;
832*86d7f5d3SJohn Marino int separator;
833*86d7f5d3SJohn Marino
834*86d7f5d3SJohn Marino pt = &delrev;
835*86d7f5d3SJohn Marino while ((c = (*++sp)) == ' ' || c == '\n' || c == '\t')
836*86d7f5d3SJohn Marino continue;
837*86d7f5d3SJohn Marino
838*86d7f5d3SJohn Marino /* Support old ambiguous '-' syntax; this will go away. */
839*86d7f5d3SJohn Marino if (strchr(sp,':'))
840*86d7f5d3SJohn Marino separator = ':';
841*86d7f5d3SJohn Marino else {
842*86d7f5d3SJohn Marino if (strchr(sp,'-') && VERSION(5) <= RCSversion)
843*86d7f5d3SJohn Marino warn("`-' is obsolete in `-o%s'; use `:' instead", sp);
844*86d7f5d3SJohn Marino separator = '-';
845*86d7f5d3SJohn Marino }
846*86d7f5d3SJohn Marino
847*86d7f5d3SJohn Marino if (c == separator) { /* -o:rev */
848*86d7f5d3SJohn Marino while ((c = (*++sp)) == ' ' || c == '\n' || c == '\t')
849*86d7f5d3SJohn Marino continue;
850*86d7f5d3SJohn Marino pt->strt = sp; pt->code = 1;
851*86d7f5d3SJohn Marino while( c != ' ' && c != '\n' && c != '\t' && c != '\0') c =(*++sp);
852*86d7f5d3SJohn Marino *sp = '\0';
853*86d7f5d3SJohn Marino pt->end = 0;
854*86d7f5d3SJohn Marino return;
855*86d7f5d3SJohn Marino }
856*86d7f5d3SJohn Marino else {
857*86d7f5d3SJohn Marino pt->strt = sp;
858*86d7f5d3SJohn Marino while( c != ' ' && c != '\n' && c != '\t' && c != '\0'
859*86d7f5d3SJohn Marino && c != separator ) c = *++sp;
860*86d7f5d3SJohn Marino *sp = '\0';
861*86d7f5d3SJohn Marino while( c == ' ' || c == '\n' || c == '\t' ) c = *++sp;
862*86d7f5d3SJohn Marino if ( c == '\0' ) { /* -o rev or branch */
863*86d7f5d3SJohn Marino pt->code = 0;
864*86d7f5d3SJohn Marino pt->end = 0;
865*86d7f5d3SJohn Marino return;
866*86d7f5d3SJohn Marino }
867*86d7f5d3SJohn Marino if (c != separator) {
868*86d7f5d3SJohn Marino error("invalid range %s %s after -o", pt->strt, sp);
869*86d7f5d3SJohn Marino }
870*86d7f5d3SJohn Marino while ((c = *++sp) == ' ' || c == '\n' || c == '\t')
871*86d7f5d3SJohn Marino continue;
872*86d7f5d3SJohn Marino if (!c) { /* -orev: */
873*86d7f5d3SJohn Marino pt->code = 2;
874*86d7f5d3SJohn Marino pt->end = 0;
875*86d7f5d3SJohn Marino return;
876*86d7f5d3SJohn Marino }
877*86d7f5d3SJohn Marino }
878*86d7f5d3SJohn Marino /* -orev1:rev2 */
879*86d7f5d3SJohn Marino pt->end = sp; pt->code = 3;
880*86d7f5d3SJohn Marino while( c!= ' ' && c != '\n' && c != '\t' && c != '\0') c = *++sp;
881*86d7f5d3SJohn Marino *sp = '\0';
882*86d7f5d3SJohn Marino }
883*86d7f5d3SJohn Marino
884*86d7f5d3SJohn Marino
885*86d7f5d3SJohn Marino
886*86d7f5d3SJohn Marino
887*86d7f5d3SJohn Marino static void
scanlogtext(delta,edit)888*86d7f5d3SJohn Marino scanlogtext(delta,edit)
889*86d7f5d3SJohn Marino struct hshentry *delta;
890*86d7f5d3SJohn Marino int edit;
891*86d7f5d3SJohn Marino /* Function: Scans delta text nodes up to and including the one given
892*86d7f5d3SJohn Marino * by delta, or up to last one present, if !delta.
893*86d7f5d3SJohn Marino * For the one given by delta (if delta), the log message is saved into
894*86d7f5d3SJohn Marino * delta->log if delta==cuttail; the text is edited if EDIT is set, else copied.
895*86d7f5d3SJohn Marino * Assumes the initial lexeme must be read in first.
896*86d7f5d3SJohn Marino * Does not advance nexttok after it is finished, except if !delta.
897*86d7f5d3SJohn Marino */
898*86d7f5d3SJohn Marino {
899*86d7f5d3SJohn Marino struct hshentry const *nextdelta;
900*86d7f5d3SJohn Marino struct cbuf cb;
901*86d7f5d3SJohn Marino
902*86d7f5d3SJohn Marino for (;;) {
903*86d7f5d3SJohn Marino foutptr = 0;
904*86d7f5d3SJohn Marino if (eoflex()) {
905*86d7f5d3SJohn Marino if(delta)
906*86d7f5d3SJohn Marino rcsfaterror("can't find delta for revision %s",
907*86d7f5d3SJohn Marino delta->num
908*86d7f5d3SJohn Marino );
909*86d7f5d3SJohn Marino return; /* no more delta text nodes */
910*86d7f5d3SJohn Marino }
911*86d7f5d3SJohn Marino nextlex();
912*86d7f5d3SJohn Marino if (!(nextdelta=getnum()))
913*86d7f5d3SJohn Marino fatserror("delta number corrupted");
914*86d7f5d3SJohn Marino if (nextdelta->selector) {
915*86d7f5d3SJohn Marino foutptr = frewrite;
916*86d7f5d3SJohn Marino aprintf(frewrite,DELNUMFORM,nextdelta->num,Klog);
917*86d7f5d3SJohn Marino }
918*86d7f5d3SJohn Marino getkeystring(Klog);
919*86d7f5d3SJohn Marino if (nextdelta == cuttail) {
920*86d7f5d3SJohn Marino cb = savestring(&curlogbuf);
921*86d7f5d3SJohn Marino if (!delta->log.string)
922*86d7f5d3SJohn Marino delta->log = cleanlogmsg(curlogbuf.string, cb.size);
923*86d7f5d3SJohn Marino nextlex();
924*86d7f5d3SJohn Marino delta->igtext = getphrases(Ktext);
925*86d7f5d3SJohn Marino } else {
926*86d7f5d3SJohn Marino if (nextdelta->log.string && nextdelta->selector) {
927*86d7f5d3SJohn Marino foutptr = 0;
928*86d7f5d3SJohn Marino readstring();
929*86d7f5d3SJohn Marino foutptr = frewrite;
930*86d7f5d3SJohn Marino putstring(foutptr, false, nextdelta->log, true);
931*86d7f5d3SJohn Marino afputc(nextc, foutptr);
932*86d7f5d3SJohn Marino } else
933*86d7f5d3SJohn Marino readstring();
934*86d7f5d3SJohn Marino ignorephrases(Ktext);
935*86d7f5d3SJohn Marino }
936*86d7f5d3SJohn Marino getkeystring(Ktext);
937*86d7f5d3SJohn Marino
938*86d7f5d3SJohn Marino if (delta==nextdelta)
939*86d7f5d3SJohn Marino break;
940*86d7f5d3SJohn Marino readstring(); /* skip over it */
941*86d7f5d3SJohn Marino
942*86d7f5d3SJohn Marino }
943*86d7f5d3SJohn Marino /* got the one we're looking for */
944*86d7f5d3SJohn Marino if (edit)
945*86d7f5d3SJohn Marino editstring((struct hshentry*)0);
946*86d7f5d3SJohn Marino else
947*86d7f5d3SJohn Marino enterstring();
948*86d7f5d3SJohn Marino }
949*86d7f5d3SJohn Marino
950*86d7f5d3SJohn Marino
951*86d7f5d3SJohn Marino
952*86d7f5d3SJohn Marino static struct Lockrev **
rmnewlocklst(which)953*86d7f5d3SJohn Marino rmnewlocklst(which)
954*86d7f5d3SJohn Marino char const *which;
955*86d7f5d3SJohn Marino /* Remove lock to revision WHICH from newlocklst. */
956*86d7f5d3SJohn Marino {
957*86d7f5d3SJohn Marino struct Lockrev *pt, **pre;
958*86d7f5d3SJohn Marino
959*86d7f5d3SJohn Marino pre = &newlocklst;
960*86d7f5d3SJohn Marino while ((pt = *pre))
961*86d7f5d3SJohn Marino if (strcmp(pt->revno, which) != 0)
962*86d7f5d3SJohn Marino pre = &pt->nextrev;
963*86d7f5d3SJohn Marino else {
964*86d7f5d3SJohn Marino *pre = pt->nextrev;
965*86d7f5d3SJohn Marino tfree(pt);
966*86d7f5d3SJohn Marino }
967*86d7f5d3SJohn Marino return pre;
968*86d7f5d3SJohn Marino }
969*86d7f5d3SJohn Marino
970*86d7f5d3SJohn Marino
971*86d7f5d3SJohn Marino
972*86d7f5d3SJohn Marino static int
doaccess()973*86d7f5d3SJohn Marino doaccess()
974*86d7f5d3SJohn Marino {
975*86d7f5d3SJohn Marino register struct chaccess *ch;
976*86d7f5d3SJohn Marino register struct access **p, *t;
977*86d7f5d3SJohn Marino register int changed = false;
978*86d7f5d3SJohn Marino
979*86d7f5d3SJohn Marino for (ch = chaccess; ch; ch = ch->nextchaccess) {
980*86d7f5d3SJohn Marino switch (ch->command) {
981*86d7f5d3SJohn Marino case erase:
982*86d7f5d3SJohn Marino if (!ch->login) {
983*86d7f5d3SJohn Marino if (AccessList) {
984*86d7f5d3SJohn Marino AccessList = 0;
985*86d7f5d3SJohn Marino changed = true;
986*86d7f5d3SJohn Marino }
987*86d7f5d3SJohn Marino } else
988*86d7f5d3SJohn Marino for (p = &AccessList; (t = *p); p = &t->nextaccess)
989*86d7f5d3SJohn Marino if (strcmp(ch->login, t->login) == 0) {
990*86d7f5d3SJohn Marino *p = t->nextaccess;
991*86d7f5d3SJohn Marino changed = true;
992*86d7f5d3SJohn Marino break;
993*86d7f5d3SJohn Marino }
994*86d7f5d3SJohn Marino break;
995*86d7f5d3SJohn Marino case append:
996*86d7f5d3SJohn Marino for (p = &AccessList; ; p = &t->nextaccess)
997*86d7f5d3SJohn Marino if (!(t = *p)) {
998*86d7f5d3SJohn Marino *p = t = ftalloc(struct access);
999*86d7f5d3SJohn Marino t->login = ch->login;
1000*86d7f5d3SJohn Marino t->nextaccess = 0;
1001*86d7f5d3SJohn Marino changed = true;
1002*86d7f5d3SJohn Marino break;
1003*86d7f5d3SJohn Marino } else if (strcmp(ch->login, t->login) == 0)
1004*86d7f5d3SJohn Marino break;
1005*86d7f5d3SJohn Marino break;
1006*86d7f5d3SJohn Marino }
1007*86d7f5d3SJohn Marino }
1008*86d7f5d3SJohn Marino return changed;
1009*86d7f5d3SJohn Marino }
1010*86d7f5d3SJohn Marino
1011*86d7f5d3SJohn Marino
1012*86d7f5d3SJohn Marino static int
sendmail(Delta,who)1013*86d7f5d3SJohn Marino sendmail(Delta, who)
1014*86d7f5d3SJohn Marino char const *Delta, *who;
1015*86d7f5d3SJohn Marino /* Function: mail to who, informing him that his lock on delta was
1016*86d7f5d3SJohn Marino * broken by caller. Ask first whether to go ahead. Return false on
1017*86d7f5d3SJohn Marino * error or if user decides not to break the lock.
1018*86d7f5d3SJohn Marino */
1019*86d7f5d3SJohn Marino {
1020*86d7f5d3SJohn Marino #ifdef SENDMAIL
1021*86d7f5d3SJohn Marino char const *messagefile;
1022*86d7f5d3SJohn Marino int old1, old2, c, status;
1023*86d7f5d3SJohn Marino FILE * mailmess;
1024*86d7f5d3SJohn Marino #endif
1025*86d7f5d3SJohn Marino
1026*86d7f5d3SJohn Marino
1027*86d7f5d3SJohn Marino aprintf(stderr, "Revision %s is already locked by %s.\n", Delta, who);
1028*86d7f5d3SJohn Marino if (suppress_mail)
1029*86d7f5d3SJohn Marino return true;
1030*86d7f5d3SJohn Marino if (!yesorno(false, "Do you want to break the lock? [ny](n): "))
1031*86d7f5d3SJohn Marino return false;
1032*86d7f5d3SJohn Marino
1033*86d7f5d3SJohn Marino /* go ahead with breaking */
1034*86d7f5d3SJohn Marino #ifdef SENDMAIL
1035*86d7f5d3SJohn Marino messagefile = maketemp(0);
1036*86d7f5d3SJohn Marino if (!(mailmess = fopenSafer(messagefile, "w+"))) {
1037*86d7f5d3SJohn Marino efaterror(messagefile);
1038*86d7f5d3SJohn Marino }
1039*86d7f5d3SJohn Marino
1040*86d7f5d3SJohn Marino aprintf(mailmess, "Subject: Broken lock on %s\n\nYour lock on revision %s of file %s\nhas been broken by %s for the following reason:\n",
1041*86d7f5d3SJohn Marino basefilename(RCSname), Delta, getfullRCSname(), getcaller()
1042*86d7f5d3SJohn Marino );
1043*86d7f5d3SJohn Marino aputs("State the reason for breaking the lock:\n(terminate with single '.' or end of file)\n>> ", stderr);
1044*86d7f5d3SJohn Marino eflush();
1045*86d7f5d3SJohn Marino
1046*86d7f5d3SJohn Marino old1 = '\n'; old2 = ' ';
1047*86d7f5d3SJohn Marino for (; ;) {
1048*86d7f5d3SJohn Marino c = getcstdin();
1049*86d7f5d3SJohn Marino if (feof(stdin)) {
1050*86d7f5d3SJohn Marino aprintf(mailmess, "%c\n", old1);
1051*86d7f5d3SJohn Marino break;
1052*86d7f5d3SJohn Marino }
1053*86d7f5d3SJohn Marino else if ( c == '\n' && old1 == '.' && old2 == '\n')
1054*86d7f5d3SJohn Marino break;
1055*86d7f5d3SJohn Marino else {
1056*86d7f5d3SJohn Marino afputc(old1, mailmess);
1057*86d7f5d3SJohn Marino old2 = old1; old1 = c;
1058*86d7f5d3SJohn Marino if (c == '\n') {
1059*86d7f5d3SJohn Marino aputs(">> ", stderr);
1060*86d7f5d3SJohn Marino eflush();
1061*86d7f5d3SJohn Marino }
1062*86d7f5d3SJohn Marino }
1063*86d7f5d3SJohn Marino }
1064*86d7f5d3SJohn Marino Orewind(mailmess);
1065*86d7f5d3SJohn Marino aflush(mailmess);
1066*86d7f5d3SJohn Marino status = run(fileno(mailmess), (char*)0, SENDMAIL, who, (char*)0);
1067*86d7f5d3SJohn Marino Ozclose(&mailmess);
1068*86d7f5d3SJohn Marino if (status == 0)
1069*86d7f5d3SJohn Marino return true;
1070*86d7f5d3SJohn Marino warn("Mail failed.");
1071*86d7f5d3SJohn Marino #endif
1072*86d7f5d3SJohn Marino warn("Mail notification of broken locks is not available.");
1073*86d7f5d3SJohn Marino warn("Please tell `%s' why you broke the lock.", who);
1074*86d7f5d3SJohn Marino return(true);
1075*86d7f5d3SJohn Marino }
1076*86d7f5d3SJohn Marino
1077*86d7f5d3SJohn Marino
1078*86d7f5d3SJohn Marino
1079*86d7f5d3SJohn Marino static int
breaklock(delta)1080*86d7f5d3SJohn Marino breaklock(delta)
1081*86d7f5d3SJohn Marino struct hshentry const *delta;
1082*86d7f5d3SJohn Marino /* function: Finds the lock held by caller on delta,
1083*86d7f5d3SJohn Marino * and removes it.
1084*86d7f5d3SJohn Marino * Sends mail if a lock different from the caller's is broken.
1085*86d7f5d3SJohn Marino * Prints an error message if there is no such lock or error.
1086*86d7f5d3SJohn Marino */
1087*86d7f5d3SJohn Marino {
1088*86d7f5d3SJohn Marino register struct rcslock *next, **trail;
1089*86d7f5d3SJohn Marino char const *num;
1090*86d7f5d3SJohn Marino
1091*86d7f5d3SJohn Marino num=delta->num;
1092*86d7f5d3SJohn Marino for (trail = &Locks; (next = *trail); trail = &next->nextlock)
1093*86d7f5d3SJohn Marino if (strcmp(num, next->delta->num) == 0) {
1094*86d7f5d3SJohn Marino if (
1095*86d7f5d3SJohn Marino strcmp(getcaller(),next->login) != 0
1096*86d7f5d3SJohn Marino && !sendmail(num, next->login)
1097*86d7f5d3SJohn Marino ) {
1098*86d7f5d3SJohn Marino rcserror("revision %s still locked by %s",
1099*86d7f5d3SJohn Marino num, next->login
1100*86d7f5d3SJohn Marino );
1101*86d7f5d3SJohn Marino return false;
1102*86d7f5d3SJohn Marino }
1103*86d7f5d3SJohn Marino diagnose("%s unlocked\n", next->delta->num);
1104*86d7f5d3SJohn Marino *trail = next->nextlock;
1105*86d7f5d3SJohn Marino next->delta->lockedby = 0;
1106*86d7f5d3SJohn Marino return true;
1107*86d7f5d3SJohn Marino }
1108*86d7f5d3SJohn Marino rcserror("no lock set on revision %s", num);
1109*86d7f5d3SJohn Marino return false;
1110*86d7f5d3SJohn Marino }
1111*86d7f5d3SJohn Marino
1112*86d7f5d3SJohn Marino
1113*86d7f5d3SJohn Marino
1114*86d7f5d3SJohn Marino static struct hshentry *
searchcutpt(object,length,store)1115*86d7f5d3SJohn Marino searchcutpt(object, length, store)
1116*86d7f5d3SJohn Marino char const *object;
1117*86d7f5d3SJohn Marino int length;
1118*86d7f5d3SJohn Marino struct hshentries *store;
1119*86d7f5d3SJohn Marino /* Function: Search store and return entry with number being object. */
1120*86d7f5d3SJohn Marino /* cuttail = 0, if the entry is Head; otherwise, cuttail */
1121*86d7f5d3SJohn Marino /* is the entry point to the one with number being object */
1122*86d7f5d3SJohn Marino
1123*86d7f5d3SJohn Marino {
1124*86d7f5d3SJohn Marino cuthead = 0;
1125*86d7f5d3SJohn Marino while (compartial(store->first->num, object, length)) {
1126*86d7f5d3SJohn Marino cuthead = store->first;
1127*86d7f5d3SJohn Marino store = store->rest;
1128*86d7f5d3SJohn Marino }
1129*86d7f5d3SJohn Marino return store->first;
1130*86d7f5d3SJohn Marino }
1131*86d7f5d3SJohn Marino
1132*86d7f5d3SJohn Marino
1133*86d7f5d3SJohn Marino
1134*86d7f5d3SJohn Marino static int
branchpoint(strt,tail)1135*86d7f5d3SJohn Marino branchpoint(strt, tail)
1136*86d7f5d3SJohn Marino struct hshentry *strt, *tail;
1137*86d7f5d3SJohn Marino /* Function: check whether the deltas between strt and tail */
1138*86d7f5d3SJohn Marino /* are locked or branch point, return 1 if any is */
1139*86d7f5d3SJohn Marino /* locked or branch point; otherwise, return 0 and */
1140*86d7f5d3SJohn Marino /* mark deleted */
1141*86d7f5d3SJohn Marino
1142*86d7f5d3SJohn Marino {
1143*86d7f5d3SJohn Marino struct hshentry *pt;
1144*86d7f5d3SJohn Marino struct rcslock const *lockpt;
1145*86d7f5d3SJohn Marino
1146*86d7f5d3SJohn Marino for (pt = strt; pt != tail; pt = pt->next) {
1147*86d7f5d3SJohn Marino if ( pt->branches ){ /* a branch point */
1148*86d7f5d3SJohn Marino rcserror("can't remove branch point %s", pt->num);
1149*86d7f5d3SJohn Marino return true;
1150*86d7f5d3SJohn Marino }
1151*86d7f5d3SJohn Marino for (lockpt = Locks; lockpt; lockpt = lockpt->nextlock)
1152*86d7f5d3SJohn Marino if (lockpt->delta == pt) {
1153*86d7f5d3SJohn Marino rcserror("can't remove locked revision %s", pt->num);
1154*86d7f5d3SJohn Marino return true;
1155*86d7f5d3SJohn Marino }
1156*86d7f5d3SJohn Marino pt->selector = false;
1157*86d7f5d3SJohn Marino diagnose("deleting revision %s\n",pt->num);
1158*86d7f5d3SJohn Marino }
1159*86d7f5d3SJohn Marino return false;
1160*86d7f5d3SJohn Marino }
1161*86d7f5d3SJohn Marino
1162*86d7f5d3SJohn Marino
1163*86d7f5d3SJohn Marino
1164*86d7f5d3SJohn Marino static int
removerevs()1165*86d7f5d3SJohn Marino removerevs()
1166*86d7f5d3SJohn Marino /* Function: get the revision range to be removed, and place the */
1167*86d7f5d3SJohn Marino /* first revision removed in delstrt, the revision before */
1168*86d7f5d3SJohn Marino /* delstrt in cuthead (0, if delstrt is head), and the */
1169*86d7f5d3SJohn Marino /* revision after the last removed revision in cuttail (0 */
1170*86d7f5d3SJohn Marino /* if the last is a leaf */
1171*86d7f5d3SJohn Marino
1172*86d7f5d3SJohn Marino {
1173*86d7f5d3SJohn Marino struct hshentry *target, *target2, *temp;
1174*86d7f5d3SJohn Marino int length;
1175*86d7f5d3SJohn Marino int cmp;
1176*86d7f5d3SJohn Marino
1177*86d7f5d3SJohn Marino if (!expandsym(delrev.strt, &numrev)) return 0;
1178*86d7f5d3SJohn Marino target = genrevs(numrev.string,(char*)0,(char*)0,(char*)0,&gendeltas);
1179*86d7f5d3SJohn Marino if ( ! target ) return 0;
1180*86d7f5d3SJohn Marino cmp = cmpnum(target->num, numrev.string);
1181*86d7f5d3SJohn Marino length = countnumflds(numrev.string);
1182*86d7f5d3SJohn Marino
1183*86d7f5d3SJohn Marino if (delrev.code == 0) { /* -o rev or -o branch */
1184*86d7f5d3SJohn Marino if (length & 1)
1185*86d7f5d3SJohn Marino temp=searchcutpt(target->num,length+1,gendeltas);
1186*86d7f5d3SJohn Marino else if (cmp) {
1187*86d7f5d3SJohn Marino rcserror("Revision %s doesn't exist.", numrev.string);
1188*86d7f5d3SJohn Marino return 0;
1189*86d7f5d3SJohn Marino }
1190*86d7f5d3SJohn Marino else
1191*86d7f5d3SJohn Marino temp = searchcutpt(numrev.string, length, gendeltas);
1192*86d7f5d3SJohn Marino cuttail = target->next;
1193*86d7f5d3SJohn Marino if ( branchpoint(temp, cuttail) ) {
1194*86d7f5d3SJohn Marino cuttail = 0;
1195*86d7f5d3SJohn Marino return 0;
1196*86d7f5d3SJohn Marino }
1197*86d7f5d3SJohn Marino delstrt = temp; /* first revision to be removed */
1198*86d7f5d3SJohn Marino return 1;
1199*86d7f5d3SJohn Marino }
1200*86d7f5d3SJohn Marino
1201*86d7f5d3SJohn Marino if (length & 1) { /* invalid branch after -o */
1202*86d7f5d3SJohn Marino rcserror("invalid branch range %s after -o", numrev.string);
1203*86d7f5d3SJohn Marino return 0;
1204*86d7f5d3SJohn Marino }
1205*86d7f5d3SJohn Marino
1206*86d7f5d3SJohn Marino if (delrev.code == 1) { /* -o -rev */
1207*86d7f5d3SJohn Marino if ( length > 2 ) {
1208*86d7f5d3SJohn Marino temp = searchcutpt( target->num, length-1, gendeltas);
1209*86d7f5d3SJohn Marino cuttail = target->next;
1210*86d7f5d3SJohn Marino }
1211*86d7f5d3SJohn Marino else {
1212*86d7f5d3SJohn Marino temp = searchcutpt(target->num, length, gendeltas);
1213*86d7f5d3SJohn Marino cuttail = target;
1214*86d7f5d3SJohn Marino while( cuttail && ! cmpnumfld(target->num,cuttail->num,1) )
1215*86d7f5d3SJohn Marino cuttail = cuttail->next;
1216*86d7f5d3SJohn Marino }
1217*86d7f5d3SJohn Marino if ( branchpoint(temp, cuttail) ){
1218*86d7f5d3SJohn Marino cuttail = 0;
1219*86d7f5d3SJohn Marino return 0;
1220*86d7f5d3SJohn Marino }
1221*86d7f5d3SJohn Marino delstrt = temp;
1222*86d7f5d3SJohn Marino return 1;
1223*86d7f5d3SJohn Marino }
1224*86d7f5d3SJohn Marino
1225*86d7f5d3SJohn Marino if (delrev.code == 2) { /* -o rev- */
1226*86d7f5d3SJohn Marino if ( length == 2 ) {
1227*86d7f5d3SJohn Marino temp = searchcutpt(target->num, 1,gendeltas);
1228*86d7f5d3SJohn Marino if (cmp)
1229*86d7f5d3SJohn Marino cuttail = target;
1230*86d7f5d3SJohn Marino else
1231*86d7f5d3SJohn Marino cuttail = target->next;
1232*86d7f5d3SJohn Marino }
1233*86d7f5d3SJohn Marino else {
1234*86d7f5d3SJohn Marino if (cmp) {
1235*86d7f5d3SJohn Marino cuthead = target;
1236*86d7f5d3SJohn Marino if ( !(temp = target->next) ) return 0;
1237*86d7f5d3SJohn Marino }
1238*86d7f5d3SJohn Marino else
1239*86d7f5d3SJohn Marino temp = searchcutpt(target->num, length, gendeltas);
1240*86d7f5d3SJohn Marino getbranchno(temp->num, &numrev); /* get branch number */
1241*86d7f5d3SJohn Marino VOID genrevs(numrev.string, (char*)0, (char*)0, (char*)0, &gendeltas);
1242*86d7f5d3SJohn Marino }
1243*86d7f5d3SJohn Marino if ( branchpoint( temp, cuttail ) ) {
1244*86d7f5d3SJohn Marino cuttail = 0;
1245*86d7f5d3SJohn Marino return 0;
1246*86d7f5d3SJohn Marino }
1247*86d7f5d3SJohn Marino delstrt = temp;
1248*86d7f5d3SJohn Marino return 1;
1249*86d7f5d3SJohn Marino }
1250*86d7f5d3SJohn Marino
1251*86d7f5d3SJohn Marino /* -o rev1-rev2 */
1252*86d7f5d3SJohn Marino if (!expandsym(delrev.end, &numrev)) return 0;
1253*86d7f5d3SJohn Marino if (
1254*86d7f5d3SJohn Marino length != countnumflds(numrev.string)
1255*86d7f5d3SJohn Marino || (length>2 && compartial(numrev.string, target->num, length-1))
1256*86d7f5d3SJohn Marino ) {
1257*86d7f5d3SJohn Marino rcserror("invalid revision range %s-%s",
1258*86d7f5d3SJohn Marino target->num, numrev.string
1259*86d7f5d3SJohn Marino );
1260*86d7f5d3SJohn Marino return 0;
1261*86d7f5d3SJohn Marino }
1262*86d7f5d3SJohn Marino
1263*86d7f5d3SJohn Marino target2 = genrevs(numrev.string,(char*)0,(char*)0,(char*)0,&gendeltas);
1264*86d7f5d3SJohn Marino if ( ! target2 ) return 0;
1265*86d7f5d3SJohn Marino
1266*86d7f5d3SJohn Marino if ( length > 2) { /* delete revisions on branches */
1267*86d7f5d3SJohn Marino if ( cmpnum(target->num, target2->num) > 0) {
1268*86d7f5d3SJohn Marino cmp = cmpnum(target2->num, numrev.string);
1269*86d7f5d3SJohn Marino temp = target;
1270*86d7f5d3SJohn Marino target = target2;
1271*86d7f5d3SJohn Marino target2 = temp;
1272*86d7f5d3SJohn Marino }
1273*86d7f5d3SJohn Marino if (cmp) {
1274*86d7f5d3SJohn Marino if ( ! cmpnum(target->num, target2->num) ) {
1275*86d7f5d3SJohn Marino rcserror("Revisions %s-%s don't exist.",
1276*86d7f5d3SJohn Marino delrev.strt, delrev.end
1277*86d7f5d3SJohn Marino );
1278*86d7f5d3SJohn Marino return 0;
1279*86d7f5d3SJohn Marino }
1280*86d7f5d3SJohn Marino cuthead = target;
1281*86d7f5d3SJohn Marino temp = target->next;
1282*86d7f5d3SJohn Marino }
1283*86d7f5d3SJohn Marino else
1284*86d7f5d3SJohn Marino temp = searchcutpt(target->num, length, gendeltas);
1285*86d7f5d3SJohn Marino cuttail = target2->next;
1286*86d7f5d3SJohn Marino }
1287*86d7f5d3SJohn Marino else { /* delete revisions on trunk */
1288*86d7f5d3SJohn Marino if ( cmpnum( target->num, target2->num) < 0 ) {
1289*86d7f5d3SJohn Marino temp = target;
1290*86d7f5d3SJohn Marino target = target2;
1291*86d7f5d3SJohn Marino target2 = temp;
1292*86d7f5d3SJohn Marino }
1293*86d7f5d3SJohn Marino else
1294*86d7f5d3SJohn Marino cmp = cmpnum(target2->num, numrev.string);
1295*86d7f5d3SJohn Marino if (cmp) {
1296*86d7f5d3SJohn Marino if ( ! cmpnum(target->num, target2->num) ) {
1297*86d7f5d3SJohn Marino rcserror("Revisions %s-%s don't exist.",
1298*86d7f5d3SJohn Marino delrev.strt, delrev.end
1299*86d7f5d3SJohn Marino );
1300*86d7f5d3SJohn Marino return 0;
1301*86d7f5d3SJohn Marino }
1302*86d7f5d3SJohn Marino cuttail = target2;
1303*86d7f5d3SJohn Marino }
1304*86d7f5d3SJohn Marino else
1305*86d7f5d3SJohn Marino cuttail = target2->next;
1306*86d7f5d3SJohn Marino temp = searchcutpt(target->num, length, gendeltas);
1307*86d7f5d3SJohn Marino }
1308*86d7f5d3SJohn Marino if ( branchpoint(temp, cuttail) ) {
1309*86d7f5d3SJohn Marino cuttail = 0;
1310*86d7f5d3SJohn Marino return 0;
1311*86d7f5d3SJohn Marino }
1312*86d7f5d3SJohn Marino delstrt = temp;
1313*86d7f5d3SJohn Marino return 1;
1314*86d7f5d3SJohn Marino }
1315*86d7f5d3SJohn Marino
1316*86d7f5d3SJohn Marino
1317*86d7f5d3SJohn Marino
1318*86d7f5d3SJohn Marino static int
doassoc()1319*86d7f5d3SJohn Marino doassoc()
1320*86d7f5d3SJohn Marino /* Add or delete (if !revno) association that is stored in assoclst. */
1321*86d7f5d3SJohn Marino {
1322*86d7f5d3SJohn Marino char const *p;
1323*86d7f5d3SJohn Marino int changed = false;
1324*86d7f5d3SJohn Marino struct Symrev const *curassoc;
1325*86d7f5d3SJohn Marino struct assoc **pre, *pt;
1326*86d7f5d3SJohn Marino
1327*86d7f5d3SJohn Marino /* add new associations */
1328*86d7f5d3SJohn Marino for (curassoc = assoclst; curassoc; curassoc = curassoc->nextsym) {
1329*86d7f5d3SJohn Marino char const *ssymbol = curassoc->ssymbol;
1330*86d7f5d3SJohn Marino
1331*86d7f5d3SJohn Marino if (!curassoc->revno) { /* delete symbol */
1332*86d7f5d3SJohn Marino for (pre = &Symbols; ; pre = &pt->nextassoc)
1333*86d7f5d3SJohn Marino if (!(pt = *pre)) {
1334*86d7f5d3SJohn Marino rcswarn("can't delete nonexisting symbol %s", ssymbol);
1335*86d7f5d3SJohn Marino break;
1336*86d7f5d3SJohn Marino } else if (strcmp(pt->symbol, ssymbol) == 0) {
1337*86d7f5d3SJohn Marino *pre = pt->nextassoc;
1338*86d7f5d3SJohn Marino changed = true;
1339*86d7f5d3SJohn Marino break;
1340*86d7f5d3SJohn Marino }
1341*86d7f5d3SJohn Marino }
1342*86d7f5d3SJohn Marino else {
1343*86d7f5d3SJohn Marino if (curassoc->revno[0]) {
1344*86d7f5d3SJohn Marino p = 0;
1345*86d7f5d3SJohn Marino if (expandsym(curassoc->revno, &numrev))
1346*86d7f5d3SJohn Marino p = fstr_save(numrev.string);
1347*86d7f5d3SJohn Marino } else if (!(p = tiprev()))
1348*86d7f5d3SJohn Marino rcserror("no latest revision to associate with symbol %s",
1349*86d7f5d3SJohn Marino ssymbol
1350*86d7f5d3SJohn Marino );
1351*86d7f5d3SJohn Marino if (p)
1352*86d7f5d3SJohn Marino changed |= addsymbol(p, ssymbol, curassoc->override);
1353*86d7f5d3SJohn Marino }
1354*86d7f5d3SJohn Marino }
1355*86d7f5d3SJohn Marino return changed;
1356*86d7f5d3SJohn Marino }
1357*86d7f5d3SJohn Marino
1358*86d7f5d3SJohn Marino
1359*86d7f5d3SJohn Marino
1360*86d7f5d3SJohn Marino static int
dolocks()1361*86d7f5d3SJohn Marino dolocks()
1362*86d7f5d3SJohn Marino /* Function: remove lock for caller or first lock if unlockcaller is set;
1363*86d7f5d3SJohn Marino * remove locks which are stored in rmvlocklst,
1364*86d7f5d3SJohn Marino * add new locks which are stored in newlocklst,
1365*86d7f5d3SJohn Marino * add lock for Dbranch or Head if lockhead is set.
1366*86d7f5d3SJohn Marino */
1367*86d7f5d3SJohn Marino {
1368*86d7f5d3SJohn Marino struct Lockrev const *lockpt;
1369*86d7f5d3SJohn Marino struct hshentry *target;
1370*86d7f5d3SJohn Marino int changed = false;
1371*86d7f5d3SJohn Marino
1372*86d7f5d3SJohn Marino if (unlockcaller) { /* find lock for caller */
1373*86d7f5d3SJohn Marino if ( Head ) {
1374*86d7f5d3SJohn Marino if (Locks) {
1375*86d7f5d3SJohn Marino switch (findlock(true, &target)) {
1376*86d7f5d3SJohn Marino case 0:
1377*86d7f5d3SJohn Marino /* remove most recent lock */
1378*86d7f5d3SJohn Marino changed |= breaklock(Locks->delta);
1379*86d7f5d3SJohn Marino break;
1380*86d7f5d3SJohn Marino case 1:
1381*86d7f5d3SJohn Marino diagnose("%s unlocked\n",target->num);
1382*86d7f5d3SJohn Marino changed = true;
1383*86d7f5d3SJohn Marino break;
1384*86d7f5d3SJohn Marino }
1385*86d7f5d3SJohn Marino } else {
1386*86d7f5d3SJohn Marino rcswarn("No locks are set.");
1387*86d7f5d3SJohn Marino }
1388*86d7f5d3SJohn Marino } else {
1389*86d7f5d3SJohn Marino rcswarn("can't unlock an empty tree");
1390*86d7f5d3SJohn Marino }
1391*86d7f5d3SJohn Marino }
1392*86d7f5d3SJohn Marino
1393*86d7f5d3SJohn Marino /* remove locks which are stored in rmvlocklst */
1394*86d7f5d3SJohn Marino for (lockpt = rmvlocklst; lockpt; lockpt = lockpt->nextrev)
1395*86d7f5d3SJohn Marino if (expandsym(lockpt->revno, &numrev)) {
1396*86d7f5d3SJohn Marino target = genrevs(numrev.string, (char *)0, (char *)0, (char *)0, &gendeltas);
1397*86d7f5d3SJohn Marino if ( target ) {
1398*86d7f5d3SJohn Marino if (!(countnumflds(numrev.string)&1) && cmpnum(target->num,numrev.string))
1399*86d7f5d3SJohn Marino rcserror("can't unlock nonexisting revision %s",
1400*86d7f5d3SJohn Marino lockpt->revno
1401*86d7f5d3SJohn Marino );
1402*86d7f5d3SJohn Marino else
1403*86d7f5d3SJohn Marino changed |= breaklock(target);
1404*86d7f5d3SJohn Marino /* breaklock does its own diagnose */
1405*86d7f5d3SJohn Marino }
1406*86d7f5d3SJohn Marino }
1407*86d7f5d3SJohn Marino
1408*86d7f5d3SJohn Marino /* add new locks which stored in newlocklst */
1409*86d7f5d3SJohn Marino for (lockpt = newlocklst; lockpt; lockpt = lockpt->nextrev)
1410*86d7f5d3SJohn Marino changed |= setlock(lockpt->revno);
1411*86d7f5d3SJohn Marino
1412*86d7f5d3SJohn Marino if (lockhead) { /* lock default branch or head */
1413*86d7f5d3SJohn Marino if (Dbranch)
1414*86d7f5d3SJohn Marino changed |= setlock(Dbranch);
1415*86d7f5d3SJohn Marino else if (Head)
1416*86d7f5d3SJohn Marino changed |= setlock(Head->num);
1417*86d7f5d3SJohn Marino else
1418*86d7f5d3SJohn Marino rcswarn("can't lock an empty tree");
1419*86d7f5d3SJohn Marino }
1420*86d7f5d3SJohn Marino return changed;
1421*86d7f5d3SJohn Marino }
1422*86d7f5d3SJohn Marino
1423*86d7f5d3SJohn Marino
1424*86d7f5d3SJohn Marino
1425*86d7f5d3SJohn Marino static int
setlock(rev)1426*86d7f5d3SJohn Marino setlock(rev)
1427*86d7f5d3SJohn Marino char const *rev;
1428*86d7f5d3SJohn Marino /* Function: Given a revision or branch number, finds the corresponding
1429*86d7f5d3SJohn Marino * delta and locks it for caller.
1430*86d7f5d3SJohn Marino */
1431*86d7f5d3SJohn Marino {
1432*86d7f5d3SJohn Marino struct hshentry *target;
1433*86d7f5d3SJohn Marino int r;
1434*86d7f5d3SJohn Marino
1435*86d7f5d3SJohn Marino if (expandsym(rev, &numrev)) {
1436*86d7f5d3SJohn Marino target = genrevs(numrev.string, (char*)0, (char*)0,
1437*86d7f5d3SJohn Marino (char*)0, &gendeltas);
1438*86d7f5d3SJohn Marino if ( target ) {
1439*86d7f5d3SJohn Marino if (!(countnumflds(numrev.string)&1) && cmpnum(target->num,numrev.string))
1440*86d7f5d3SJohn Marino rcserror("can't lock nonexisting revision %s",
1441*86d7f5d3SJohn Marino numrev.string
1442*86d7f5d3SJohn Marino );
1443*86d7f5d3SJohn Marino else {
1444*86d7f5d3SJohn Marino if ((r = addlock(target, false)) < 0 && breaklock(target))
1445*86d7f5d3SJohn Marino r = addlock(target, true);
1446*86d7f5d3SJohn Marino if (0 <= r) {
1447*86d7f5d3SJohn Marino if (r)
1448*86d7f5d3SJohn Marino diagnose("%s locked\n", target->num);
1449*86d7f5d3SJohn Marino return r;
1450*86d7f5d3SJohn Marino }
1451*86d7f5d3SJohn Marino }
1452*86d7f5d3SJohn Marino }
1453*86d7f5d3SJohn Marino }
1454*86d7f5d3SJohn Marino return 0;
1455*86d7f5d3SJohn Marino }
1456*86d7f5d3SJohn Marino
1457*86d7f5d3SJohn Marino
1458*86d7f5d3SJohn Marino static int
domessages()1459*86d7f5d3SJohn Marino domessages()
1460*86d7f5d3SJohn Marino {
1461*86d7f5d3SJohn Marino struct hshentry *target;
1462*86d7f5d3SJohn Marino struct Message *p;
1463*86d7f5d3SJohn Marino int changed = false;
1464*86d7f5d3SJohn Marino
1465*86d7f5d3SJohn Marino for (p = messagelst; p; p = p->nextmessage)
1466*86d7f5d3SJohn Marino if (
1467*86d7f5d3SJohn Marino expandsym(p->revno, &numrev) &&
1468*86d7f5d3SJohn Marino (target = genrevs(
1469*86d7f5d3SJohn Marino numrev.string, (char*)0, (char*)0, (char*)0, &gendeltas
1470*86d7f5d3SJohn Marino ))
1471*86d7f5d3SJohn Marino ) {
1472*86d7f5d3SJohn Marino /*
1473*86d7f5d3SJohn Marino * We can't check the old log -- it's much later in the file.
1474*86d7f5d3SJohn Marino * We pessimistically assume that it changed.
1475*86d7f5d3SJohn Marino */
1476*86d7f5d3SJohn Marino target->log = p->message;
1477*86d7f5d3SJohn Marino changed = true;
1478*86d7f5d3SJohn Marino }
1479*86d7f5d3SJohn Marino return changed;
1480*86d7f5d3SJohn Marino }
1481*86d7f5d3SJohn Marino
1482*86d7f5d3SJohn Marino
1483*86d7f5d3SJohn Marino static int
rcs_setstate(rev,status)1484*86d7f5d3SJohn Marino rcs_setstate(rev,status)
1485*86d7f5d3SJohn Marino char const *rev, *status;
1486*86d7f5d3SJohn Marino /* Function: Given a revision or branch number, finds the corresponding delta
1487*86d7f5d3SJohn Marino * and sets its state to status.
1488*86d7f5d3SJohn Marino */
1489*86d7f5d3SJohn Marino {
1490*86d7f5d3SJohn Marino struct hshentry *target;
1491*86d7f5d3SJohn Marino
1492*86d7f5d3SJohn Marino if (expandsym(rev, &numrev)) {
1493*86d7f5d3SJohn Marino target = genrevs(numrev.string, (char*)0, (char*)0,
1494*86d7f5d3SJohn Marino (char*)0, &gendeltas);
1495*86d7f5d3SJohn Marino if ( target ) {
1496*86d7f5d3SJohn Marino if (!(countnumflds(numrev.string)&1) && cmpnum(target->num,numrev.string))
1497*86d7f5d3SJohn Marino rcserror("can't set state of nonexisting revision %s",
1498*86d7f5d3SJohn Marino numrev.string
1499*86d7f5d3SJohn Marino );
1500*86d7f5d3SJohn Marino else if (strcmp(target->state, status) != 0) {
1501*86d7f5d3SJohn Marino target->state = status;
1502*86d7f5d3SJohn Marino return true;
1503*86d7f5d3SJohn Marino }
1504*86d7f5d3SJohn Marino }
1505*86d7f5d3SJohn Marino }
1506*86d7f5d3SJohn Marino return false;
1507*86d7f5d3SJohn Marino }
1508*86d7f5d3SJohn Marino
1509*86d7f5d3SJohn Marino
1510*86d7f5d3SJohn Marino
1511*86d7f5d3SJohn Marino
1512*86d7f5d3SJohn Marino
1513*86d7f5d3SJohn Marino static int
buildeltatext(deltas)1514*86d7f5d3SJohn Marino buildeltatext(deltas)
1515*86d7f5d3SJohn Marino struct hshentries const *deltas;
1516*86d7f5d3SJohn Marino /* Function: put the delta text on frewrite and make necessary */
1517*86d7f5d3SJohn Marino /* change to delta text */
1518*86d7f5d3SJohn Marino {
1519*86d7f5d3SJohn Marino register FILE *fcut; /* temporary file to rebuild delta tree */
1520*86d7f5d3SJohn Marino char const *cutname;
1521*86d7f5d3SJohn Marino
1522*86d7f5d3SJohn Marino fcut = 0;
1523*86d7f5d3SJohn Marino cuttail->selector = false;
1524*86d7f5d3SJohn Marino scanlogtext(deltas->first, false);
1525*86d7f5d3SJohn Marino if ( cuthead ) {
1526*86d7f5d3SJohn Marino cutname = maketemp(3);
1527*86d7f5d3SJohn Marino if (!(fcut = fopenSafer(cutname, FOPEN_WPLUS_WORK))) {
1528*86d7f5d3SJohn Marino efaterror(cutname);
1529*86d7f5d3SJohn Marino }
1530*86d7f5d3SJohn Marino
1531*86d7f5d3SJohn Marino while (deltas->first != cuthead) {
1532*86d7f5d3SJohn Marino deltas = deltas->rest;
1533*86d7f5d3SJohn Marino scanlogtext(deltas->first, true);
1534*86d7f5d3SJohn Marino }
1535*86d7f5d3SJohn Marino
1536*86d7f5d3SJohn Marino snapshotedit(fcut);
1537*86d7f5d3SJohn Marino Orewind(fcut);
1538*86d7f5d3SJohn Marino aflush(fcut);
1539*86d7f5d3SJohn Marino }
1540*86d7f5d3SJohn Marino
1541*86d7f5d3SJohn Marino while (deltas->first != cuttail)
1542*86d7f5d3SJohn Marino scanlogtext((deltas = deltas->rest)->first, true);
1543*86d7f5d3SJohn Marino finishedit((struct hshentry*)0, (FILE*)0, true);
1544*86d7f5d3SJohn Marino Ozclose(&fcopy);
1545*86d7f5d3SJohn Marino
1546*86d7f5d3SJohn Marino if (fcut) {
1547*86d7f5d3SJohn Marino char const *diffname = maketemp(0);
1548*86d7f5d3SJohn Marino char const *diffv[6 + !!OPEN_O_BINARY];
1549*86d7f5d3SJohn Marino char const **diffp = diffv;
1550*86d7f5d3SJohn Marino *++diffp = DIFF;
1551*86d7f5d3SJohn Marino *++diffp = DIFFFLAGS;
1552*86d7f5d3SJohn Marino # if OPEN_O_BINARY
1553*86d7f5d3SJohn Marino if (Expand == BINARY_EXPAND)
1554*86d7f5d3SJohn Marino *++diffp == "--binary";
1555*86d7f5d3SJohn Marino # endif
1556*86d7f5d3SJohn Marino *++diffp = "-";
1557*86d7f5d3SJohn Marino *++diffp = resultname;
1558*86d7f5d3SJohn Marino *++diffp = 0;
1559*86d7f5d3SJohn Marino switch (runv(fileno(fcut), diffname, diffv)) {
1560*86d7f5d3SJohn Marino case DIFF_FAILURE: case DIFF_SUCCESS: break;
1561*86d7f5d3SJohn Marino default: rcsfaterror("diff failed");
1562*86d7f5d3SJohn Marino }
1563*86d7f5d3SJohn Marino Ofclose(fcut);
1564*86d7f5d3SJohn Marino return putdtext(cuttail,diffname,frewrite,true);
1565*86d7f5d3SJohn Marino } else
1566*86d7f5d3SJohn Marino return putdtext(cuttail,resultname,frewrite,false);
1567*86d7f5d3SJohn Marino }
1568*86d7f5d3SJohn Marino
1569*86d7f5d3SJohn Marino
1570*86d7f5d3SJohn Marino
1571*86d7f5d3SJohn Marino static void
buildtree()1572*86d7f5d3SJohn Marino buildtree()
1573*86d7f5d3SJohn Marino /* Function: actually removes revisions whose selector field */
1574*86d7f5d3SJohn Marino /* is false, and rebuilds the linkage of deltas. */
1575*86d7f5d3SJohn Marino /* asks for reconfirmation if deleting last revision*/
1576*86d7f5d3SJohn Marino {
1577*86d7f5d3SJohn Marino struct hshentry * Delta;
1578*86d7f5d3SJohn Marino struct branchhead *pt, *pre;
1579*86d7f5d3SJohn Marino
1580*86d7f5d3SJohn Marino if ( cuthead )
1581*86d7f5d3SJohn Marino if ( cuthead->next == delstrt )
1582*86d7f5d3SJohn Marino cuthead->next = cuttail;
1583*86d7f5d3SJohn Marino else {
1584*86d7f5d3SJohn Marino pre = pt = cuthead->branches;
1585*86d7f5d3SJohn Marino while( pt && pt->hsh != delstrt ) {
1586*86d7f5d3SJohn Marino pre = pt;
1587*86d7f5d3SJohn Marino pt = pt->nextbranch;
1588*86d7f5d3SJohn Marino }
1589*86d7f5d3SJohn Marino if ( cuttail )
1590*86d7f5d3SJohn Marino pt->hsh = cuttail;
1591*86d7f5d3SJohn Marino else if ( pt == pre )
1592*86d7f5d3SJohn Marino cuthead->branches = pt->nextbranch;
1593*86d7f5d3SJohn Marino else
1594*86d7f5d3SJohn Marino pre->nextbranch = pt->nextbranch;
1595*86d7f5d3SJohn Marino }
1596*86d7f5d3SJohn Marino else {
1597*86d7f5d3SJohn Marino if (!cuttail && !quietflag) {
1598*86d7f5d3SJohn Marino if (!yesorno(false, "Do you really want to delete all revisions? [ny](n): ")) {
1599*86d7f5d3SJohn Marino rcserror("No revision deleted");
1600*86d7f5d3SJohn Marino Delta = delstrt;
1601*86d7f5d3SJohn Marino while( Delta) {
1602*86d7f5d3SJohn Marino Delta->selector = true;
1603*86d7f5d3SJohn Marino Delta = Delta->next;
1604*86d7f5d3SJohn Marino }
1605*86d7f5d3SJohn Marino return;
1606*86d7f5d3SJohn Marino }
1607*86d7f5d3SJohn Marino }
1608*86d7f5d3SJohn Marino Head = cuttail;
1609*86d7f5d3SJohn Marino }
1610*86d7f5d3SJohn Marino return;
1611*86d7f5d3SJohn Marino }
1612*86d7f5d3SJohn Marino
1613*86d7f5d3SJohn Marino #if RCS_lint
1614*86d7f5d3SJohn Marino /* This lets us lint everything all at once. */
1615*86d7f5d3SJohn Marino
1616*86d7f5d3SJohn Marino char const cmdid[] = "";
1617*86d7f5d3SJohn Marino
1618*86d7f5d3SJohn Marino #define go(p,e) {int p P((int,char**)); void e P((void)); if(*argv)return p(argc,argv);if(*argv[1])e();}
1619*86d7f5d3SJohn Marino
1620*86d7f5d3SJohn Marino int
main(argc,argv)1621*86d7f5d3SJohn Marino main(argc, argv)
1622*86d7f5d3SJohn Marino int argc;
1623*86d7f5d3SJohn Marino char **argv;
1624*86d7f5d3SJohn Marino {
1625*86d7f5d3SJohn Marino go(ciId, ciExit);
1626*86d7f5d3SJohn Marino go(coId, coExit);
1627*86d7f5d3SJohn Marino go(identId, identExit);
1628*86d7f5d3SJohn Marino go(mergeId, mergeExit);
1629*86d7f5d3SJohn Marino go(rcsId, exiterr);
1630*86d7f5d3SJohn Marino go(rcscleanId, rcscleanExit);
1631*86d7f5d3SJohn Marino go(rcsdiffId, rdiffExit);
1632*86d7f5d3SJohn Marino go(rcsmergeId, rmergeExit);
1633*86d7f5d3SJohn Marino go(rlogId, rlogExit);
1634*86d7f5d3SJohn Marino return 0;
1635*86d7f5d3SJohn Marino }
1636*86d7f5d3SJohn Marino #endif
1637