(undigestify-rmail-message): Better error messages.
[bpt/emacs.git] / lisp / vc.el
CommitLineData
594722a8
ER
1;;; vc.el --- drive a version-control system from within Emacs
2
632e9525 3;; Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
594722a8
ER
4
5;; Author: Eric S. Raymond <esr@snark.thyrsus.com>
c6d4f628
RS
6;; Modified by:
7;; ttn@netcom.com
8;; Per Cederqvist <ceder@lysator.liu.edu>
88a2ffaf 9;; Andre Spiegel <spiegel@berlin.informatik.uni-stuttgart.de>
594722a8
ER
10
11;; This file is part of GNU Emacs.
12
13;; GNU Emacs is free software; you can redistribute it and/or modify
14;; it under the terms of the GNU General Public License as published by
15;; the Free Software Foundation; either version 2, or (at your option)
16;; any later version.
17
18;; GNU Emacs is distributed in the hope that it will be useful,
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
24;; along with GNU Emacs; see the file COPYING. If not, write to
25;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26
27;;; Commentary:
28
1a2f456b
ER
29;; This mode is fully documented in the Emacs user's manual.
30;;
594722a8
ER
31;; This was designed and implemented by Eric Raymond <esr@snark.thyrsus.com>.
32;; Paul Eggert <eggert@twinsun.com>, Sebastian Kremer <sk@thp.uni-koeln.de>,
33;; and Richard Stallman contributed valuable criticism, support, and testing.
632e9525
RS
34;; CVS support was added by Per Cederqvist <ceder@lysator.liu.se>
35;; in Jan-Feb 1994.
594722a8 36;;
632e9525 37;; Supported version-control systems presently include SCCS, RCS, and CVS.
b0c9bc8c
AS
38;;
39;; Some features will not work with old RCS versions. Where
40;; appropriate, VC finds out which version you have, and allows or
41;; disallows those features (stealing locks, for example, works only
42;; from 5.6.2 onwards).
632e9525
RS
43;; Even initial checkins will fail if your RCS version is so old that ci
44;; doesn't understand -t-; this has been known to happen to people running
45;; NExTSTEP 3.0.
594722a8 46;;
6b9d0764
AS
47;; You can support the RCS -x option by adding pairs to the
48;; vc-master-templates list.
594722a8
ER
49;;
50;; Proper function of the SCCS diff commands requires the shellscript vcdiff
51;; to be installed somewhere on Emacs's path for executables.
52;;
1a2f456b 53;; If your site uses the ChangeLog convention supported by Emacs, the
594be62e 54;; function vc-comment-to-change-log should prove a useful checkin hook.
1a2f456b 55;;
594722a8 56;; This code depends on call-process passing back the subprocess exit
e1f297e6 57;; status. Thus, you need Emacs 18.58 or later to run it. For the
6ed5075c 58;; vc-directory command to work properly as documented, you need 19.
7ef84cf9 59;; You also need Emacs 19's ring.el.
594722a8
ER
60;;
61;; The vc code maintains some internal state in order to reduce expensive
62;; version-control operations to a minimum. Some names are only computed
34291cd2 63;; once. If you perform version control operations with RCS/SCCS/CVS while
594722a8
ER
64;; vc's back is turned, or move/rename master files while vc is running,
65;; vc may get seriously confused. Don't do these things!
66;;
67;; Developer's notes on some concurrency issues are included at the end of
68;; the file.
69
70;;; Code:
71
72(require 'vc-hooks)
8c0aaf40 73(require 'ring)
5c6f8be0 74(eval-when-compile (require 'dired)) ; for dired-map-over-marks macro
8c0aaf40
ER
75
76(if (not (assoc 'vc-parent-buffer minor-mode-alist))
77 (setq minor-mode-alist
78 (cons '(vc-parent-buffer vc-parent-buffer-name)
79 minor-mode-alist)))
594722a8 80
d7eff0e0
RS
81;; To implement support for a new version-control system, add another
82;; branch to the vc-backend-dispatch macro and fill it in in each
83;; call. The variable vc-master-templates in vc-hooks.el will also
84;; have to change.
85
86(defmacro vc-backend-dispatch (f s r c)
87 "Execute FORM1, FORM2 or FORM3 for SCCS, RCS or CVS respectively.
88If FORM3 is `RCS', use FORM2 for CVS as well as RCS.
89\(CVS shares some code with RCS)."
90 (list 'let (list (list 'type (list 'vc-backend f)))
91 (list 'cond
92 (list (list 'eq 'type (quote 'SCCS)) s) ;; SCCS
93 (list (list 'eq 'type (quote 'RCS)) r) ;; RCS
94 (list (list 'eq 'type (quote 'CVS)) ;; CVS
95 (if (eq c 'RCS) r c))
96 )))
97
594722a8
ER
98;; General customization
99
594722a8 100(defvar vc-suppress-confirm nil
34291cd2 101 "*If non-nil, treat user as expert; suppress yes-no prompts on some things.")
594722a8
ER
102(defvar vc-initial-comment nil
103 "*Prompt for initial comment when a file is registered.")
104(defvar vc-command-messages nil
105 "*Display run messages from back-end commands.")
666a0ebb
RM
106(defvar vc-checkin-switches nil
107 "*Extra switches passed to the checkin program by \\[vc-checkin].")
0fb16286
RM
108(defvar vc-checkout-switches nil
109 "*Extra switches passed to the checkout program by \\[vc-checkout].")
993a1a44 110(defvar vc-directory-exclusion-list '("SCCS" "RCS" "CVS")
632e9525 111 "*Directory names ignored by functions that recursively walk file trees.")
666a0ebb 112
8c0aaf40
ER
113(defconst vc-maximum-comment-ring-size 32
114 "Maximum number of saved comments in the comment ring.")
115
2e810285
RS
116;;; This is duplicated in diff.el.
117(defvar diff-switches "-c"
118 "*A string or list of strings specifying switches to be be passed to diff.")
119
67242a23
RM
120;;;###autoload
121(defvar vc-checkin-hook nil
34291cd2 122 "*List of functions called after a checkin is done. See `run-hooks'.")
67242a23 123
80688f5c
RS
124(defvar vc-make-buffer-writable-hook nil
125 "*List of functions called when a buffer is made writable. See `run-hooks.'
126This hook is only used when the version control system is CVS. It
127might be useful for sites who uses locking with CVS, or who uses link
128farms to gold trees.")
129
594722a8
ER
130;; Header-insertion hair
131
132(defvar vc-header-alist
80688f5c 133 '((SCCS "\%W\%") (RCS "\$Id\$") (CVS "\$Id\$"))
820bde8d 134 "*Header keywords to be inserted when `vc-insert-headers' is executed.")
ba5c3004 135(defvar vc-static-header-alist
594722a8
ER
136 '(("\\.c$" .
137 "\n#ifndef lint\nstatic char vcid[] = \"\%s\";\n#endif /* lint */\n"))
138 "*Associate static header string templates with file types. A \%s in the
139template is replaced with the first string associated with the file's
34291cd2 140version-control type in `vc-header-alist'.")
7b4f934d 141
594722a8
ER
142(defvar vc-comment-alist
143 '((nroff-mode ".\\\"" ""))
144 "*Special comment delimiters to be used in generating vc headers only.
145Add an entry in this list if you need to override the normal comment-start
146and comment-end variables. This will only be necessary if the mode language
147is sensitive to blank lines.")
148
bbf97570
RS
149;; Default is to be extra careful for super-user.
150(defvar vc-checkout-carefully (= (user-uid) 0)
151 "*Non-nil means be extra-careful in checkout.
152Verify that the file really is not locked
153and that its contents match what the master file says.")
154
b0c9bc8c
AS
155(defvar vc-rcs-release nil
156 "*The release number of your RCS installation, as a string.
157If nil, VC itself computes this value when it is first needed.")
158
159(defvar vc-sccs-release nil
160 "*The release number of your SCCS installation, as a string.
161If nil, VC itself computes this value when it is first needed.")
162
163(defvar vc-cvs-release nil
164 "*The release number of your SCCS installation, as a string.
165If nil, VC itself computes this value when it is first needed.")
166
594722a8
ER
167;; Variables the user doesn't need to know about.
168(defvar vc-log-entry-mode nil)
169(defvar vc-log-operation nil)
67242a23 170(defvar vc-log-after-operation-hook nil)
34291cd2 171(defvar vc-checkout-writable-buffer-hook 'vc-checkout-writable-buffer)
dbf87856
RS
172;; In a log entry buffer, this is a local variable
173;; that points to the buffer for which it was made
174;; (either a file, or a VC dired buffer).
1a2f456b 175(defvar vc-parent-buffer nil)
8c0aaf40 176(defvar vc-parent-buffer-name nil)
594722a8 177
db59472c
RS
178(defvar vc-log-file)
179(defvar vc-log-version)
180
594722a8
ER
181(defconst vc-name-assoc-file "VC-names")
182
8c0aaf40 183(defvar vc-dired-mode nil)
e1f297e6
ER
184(make-variable-buffer-local 'vc-dired-mode)
185
8c0aaf40
ER
186(defvar vc-comment-ring nil)
187(defvar vc-comment-ring-index nil)
188(defvar vc-last-comment-match nil)
189
632e9525
RS
190;; Back-portability to Emacs 18
191
192(defun file-executable-p-18 (f)
193 (let ((modes (file-modes f)))
194 (and modes (not (zerop (logand 292))))))
195
196(defun file-regular-p-18 (f)
197 (let ((attributes (file-attributes f)))
198 (and attributes (not (car attributes)))))
199
200; Conditionally rebind some things for Emacs 18 compatibility
201(if (not (boundp 'minor-mode-map-alist))
202 (progn
203 (setq compilation-old-error-list nil)
204 (fset 'file-executable-p 'file-executable-p-18)
205 (fset 'shrink-window-if-larger-than-buffer 'beginning-of-buffer)
206 ))
207
4040437e 208(if (not (fboundp 'file-regular-p))
632e9525
RS
209 (fset 'file-regular-p 'file-regular-p-18))
210
b0c9bc8c
AS
211;;; Find and compare backend releases
212
213(defun vc-backend-release (backend)
214 ;; Returns which backend release is installed on this system.
215 (cond
216 ((eq backend 'RCS)
217 (or vc-rcs-release
218 (and (zerop (vc-do-command nil 2 "rcs" nil nil "-V"))
219 (save-excursion
220 (set-buffer (get-buffer "*vc*"))
221 (setq vc-rcs-release
222 (car (vc-parse-buffer
223 '(("^RCS version \\([0-9.]+ *.*\\)" 1)))))))
224 (setq vc-rcs-release 'unknown)))
225 ((eq backend 'CVS)
226 (or vc-cvs-release
227 (and (zerop (vc-do-command nil 1 "cvs" nil nil "-v"))
228 (save-excursion
229 (set-buffer (get-buffer "*vc*"))
230 (setq vc-cvs-release
231 (car (vc-parse-buffer
232 '(("^Concurrent Versions System (CVS) \\([0-9.]+\\)"
233 1)))))))
234 (setq vc-cvs-release 'unknown)))
235 ((eq backend 'SCCS)
236 vc-sccs-release)))
237
238(defun vc-release-greater-or-equal (r1 r2)
239 ;; Compare release numbers, represented as strings.
240 ;; Release components are assumed cardinal numbers, not decimal
241 ;; fractions (5.10 is a higher release than 5.9). Omitted fields
242 ;; are considered lower (5.6.7 is earlier than 5.6.7.1).
243 ;; Comparison runs till the end of the string is found, or a
244 ;; non-numeric component shows up (5.6.7 is earlier than "5.6.7 beta",
245 ;; which is probably not what you want in some cases).
246 ;; This code is suitable for existing RCS release numbers.
247 ;; CVS releases are handled reasonably, too (1.3 < 1.4* < 1.5).
248 (let (v1 v2 i1 i2)
249 (catch 'done
250 (or (and (string-match "^\\.?\\([0-9]+\\)" r1)
251 (setq i1 (match-end 0))
252 (setq v1 (string-to-number (match-string 1 r1)))
253 (or (and (string-match "^\\.?\\([0-9]+\\)" r2)
254 (setq i2 (match-end 0))
255 (setq v2 (string-to-number (match-string 1 r2)))
256 (if (> v1 v2) (throw 'done t)
257 (if (< v1 v2) (throw 'done nil)
258 (throw 'done
259 (vc-release-greater-or-equal
260 (substring r1 i1)
261 (substring r2 i2)))))))
262 (throw 'done t)))
263 (or (and (string-match "^\\.?\\([0-9]+\\)" r2)
264 (throw 'done nil))
265 (throw 'done t)))))
266
267(defun vc-backend-release-p (backend release)
268 ;; Return t if we have RELEASE of BACKEND or better
269 (let (i r (ri 0) (ii 0) is rs (installation (vc-backend-release backend)))
270 (if (not (eq installation 'unknown))
271 (cond
272 ((or (eq backend 'RCS) (eq backend 'CVS))
273 (vc-release-greater-or-equal installation release))))))
274
c8de1d91
AS
275;;; functions that operate on RCS revision numbers
276
277(defun vc-trunk-p (rev)
278 ;; return t if REV is a revision on the trunk
279 (not (eq nil (string-match "\\`[0-9]+\\.[0-9]+\\'" rev))))
280
281(defun vc-branch-part (rev)
282 ;; return the branch part of a revision number REV
283 (substring rev 0 (string-match "\\.[0-9]+\\'" rev)))
284
594722a8
ER
285;; File property caching
286
8c0aaf40
ER
287(defun vc-clear-context ()
288 "Clear all cached file properties and the comment ring."
289 (interactive)
290 (fillarray vc-file-prop-obarray nil)
291 ;; Note: there is potential for minor lossage here if there is an open
292 ;; log buffer with a nonzero local value of vc-comment-ring-index.
293 (setq vc-comment-ring nil))
294
88a2ffaf
RS
295(defun vc-file-clear-masterprops (file)
296 ;; clear all properties of FILE that were retrieved
297 ;; from the master file
298 (vc-file-setprop file 'vc-latest-version nil)
299 (vc-file-setprop file 'vc-your-latest-version nil)
300 (vc-backend-dispatch file
301 (progn ;; SCCS
302 (vc-file-setprop file 'vc-master-locks nil))
303 (progn ;; RCS
304 (vc-file-setprop file 'vc-default-branch nil)
305 (vc-file-setprop file 'vc-head-version nil)
8dd71345 306 (vc-file-setprop file 'vc-master-workfile-version nil)
88a2ffaf
RS
307 (vc-file-setprop file 'vc-master-locks nil))
308 (progn
309 (vc-file-setprop file 'vc-cvs-status nil))))
f3c61d82 310
c8de1d91
AS
311(defun vc-head-version (file)
312 ;; Return the RCS head version of FILE
313 (cond ((vc-file-getprop file 'vc-head-version))
314 (t (vc-fetch-master-properties file)
315 (vc-file-getprop file 'vc-head-version))))
f3c61d82 316
594722a8
ER
317;; Random helper functions
318
c8de1d91
AS
319(defun vc-latest-on-branch-p (file)
320 ;; return t iff the current workfile version of FILE is
321 ;; the latest on its branch.
322 (vc-backend-dispatch file
323 ;; SCCS
324 (string= (vc-workfile-version file) (vc-latest-version file))
325 ;; RCS
326 (let ((workfile-version (vc-workfile-version file)) tip-version)
327 (if (vc-trunk-p workfile-version)
328 (progn
329 ;; Re-fetch the head version number. This is to make
330 ;; sure that no-one has checked in a new version behind
331 ;; our back.
332 (vc-fetch-master-properties file)
333 (string= (vc-file-getprop file 'vc-head-version)
334 workfile-version))
335 ;; If we are not on the trunk, we need to examine the
7d88be52
AS
336 ;; whole current branch. (vc-master-workfile-version
337 ;; is not what we need.)
c8de1d91
AS
338 (save-excursion
339 (set-buffer (get-buffer-create "*vc-info*"))
340 (vc-insert-file (vc-name file) "^desc")
341 (setq tip-version (car (vc-parse-buffer (list (list
342 (concat "^\\(" (regexp-quote (vc-branch-part workfile-version))
343 "\\.[0-9]+\\)\ndate[ \t]+\\([0-9.]+\\);") 1 2)))))
344 (if (get-buffer "*vc-info*")
345 (kill-buffer (get-buffer "*vc-info*")))
346 (string= tip-version workfile-version))))
347 ;; CVS
8dd71345 348 t))
c8de1d91 349
7ef84cf9
RS
350(defun vc-registration-error (file)
351 (if file
590cc449
RS
352 (error "File %s is not under version control" file)
353 (error "Buffer %s is not associated with a file" (buffer-name))))
7ef84cf9 354
594722a8
ER
355(defvar vc-binary-assoc nil)
356
357(defun vc-find-binary (name)
358 "Look for a command anywhere on the subprocess-command search path."
359 (or (cdr (assoc name vc-binary-assoc))
deb9ebc6
PE
360 (catch 'found
361 (mapcar
362 (function
363 (lambda (s)
364 (if s
365 (let ((full (concat s "/" name)))
366 (if (file-executable-p full)
367 (progn
368 (setq vc-binary-assoc
369 (cons (cons name full) vc-binary-assoc))
370 (throw 'found full)))))))
371 exec-path)
372 nil)))
594722a8 373
6aa13729 374(defun vc-do-command (buffer okstatus command file last &rest flags)
594722a8 375 "Execute a version-control command, notifying user and checking for errors.
6aa13729 376Output from COMMAND goes to BUFFER, or *vc* if BUFFER is nil.
594722a8 377The command is successful if its exit status does not exceed OKSTATUS.
6aa13729
RS
378The last argument of the command is the master name of FILE if LAST is
379`MASTER', or the workfile of FILE if LAST is `WORKFILE'; this is appended
380to an optional list of FLAGS."
b0c9bc8c 381 (and file (setq file (expand-file-name file)))
6aa13729 382 (if (not buffer) (setq buffer "*vc*"))
594722a8 383 (if vc-command-messages
02da6253 384 (message "Running %s on %s..." command file))
1a2f456b 385 (let ((obuf (current-buffer)) (camefrom (current-buffer))
594722a8
ER
386 (squeezed nil)
387 (vc-file (and file (vc-name file)))
632e9525 388 (olddir default-directory)
594722a8 389 status)
6aa13729 390 (set-buffer (get-buffer-create buffer))
8c0aaf40
ER
391 (set (make-local-variable 'vc-parent-buffer) camefrom)
392 (set (make-local-variable 'vc-parent-buffer-name)
393 (concat " from " (buffer-name camefrom)))
632e9525 394 (setq default-directory olddir)
8c0aaf40 395
594722a8 396 (erase-buffer)
315e49ed 397
594722a8
ER
398 (mapcar
399 (function (lambda (s) (and s (setq squeezed (append squeezed (list s))))))
400 flags)
80688f5c 401 (if (and vc-file (eq last 'MASTER))
594722a8 402 (setq squeezed (append squeezed (list vc-file))))
632e9525
RS
403 (if (eq last 'WORKFILE)
404 (progn
405 (let* ((pwd (expand-file-name default-directory))
406 (preflen (length pwd)))
407 (if (string= (substring file 0 preflen) pwd)
408 (setq file (substring file preflen))))
409 (setq squeezed (append squeezed (list file)))))
46cd263f 410 (let ((exec-path (append vc-path exec-path))
eadcb02c
RS
411 ;; Add vc-path to PATH for the execution of this command.
412 (process-environment
413 (cons (concat "PATH=" (getenv "PATH")
993a1a44
RS
414 path-separator
415 (mapconcat 'identity vc-path path-separator))
eadcb02c 416 process-environment)))
1a2f456b 417 (setq status (apply 'call-process command nil t nil squeezed)))
594722a8 418 (goto-char (point-max))
632e9525 419 (set-buffer-modified-p nil)
4805f679 420 (forward-line -1)
594722a8
ER
421 (if (or (not (integerp status)) (< okstatus status))
422 (progn
6aa13729 423 (pop-to-buffer buffer)
594722a8 424 (goto-char (point-min))
4c2d8cf9 425 (shrink-window-if-larger-than-buffer)
02da6253
PE
426 (error "Running %s...FAILED (%s)" command
427 (if (integerp status)
428 (format "status %d" status)
429 status))
594722a8
ER
430 )
431 (if vc-command-messages
02da6253 432 (message "Running %s...OK" command))
594722a8
ER
433 )
434 (set-buffer obuf)
435 status)
436 )
437
c4ae7096
JB
438;;; Save a bit of the text around POSN in the current buffer, to help
439;;; us find the corresponding position again later. This works even
440;;; if all markers are destroyed or corrupted.
c8de1d91 441;;; A lot of this was shamelessly lifted from Sebastian Kremer's rcs.el mode.
c4ae7096
JB
442(defun vc-position-context (posn)
443 (list posn
444 (buffer-size)
445 (buffer-substring posn
446 (min (point-max) (+ posn 100)))))
447
448;;; Return the position of CONTEXT in the current buffer, or nil if we
449;;; couldn't find it.
450(defun vc-find-position-by-context (context)
451 (let ((context-string (nth 2 context)))
452 (if (equal "" context-string)
453 (point-max)
454 (save-excursion
455 (let ((diff (- (nth 1 context) (buffer-size))))
456 (if (< diff 0) (setq diff (- diff)))
457 (goto-char (nth 0 context))
458 (if (or (search-forward context-string nil t)
459 ;; Can't use search-backward since the match may continue
460 ;; after point.
461 (progn (goto-char (- (point) diff (length context-string)))
462 ;; goto-char doesn't signal an error at
463 ;; beginning of buffer like backward-char would
464 (search-forward context-string nil t)))
465 ;; to beginning of OSTRING
466 (- (point) (length context-string))))))))
467
c8de1d91
AS
468(defun vc-buffer-context ()
469 ;; Return a list '(point-context mark-context reparse); from which
470 ;; vc-restore-buffer-context can later restore the context.
c4ae7096 471 (let ((point-context (vc-position-context (point)))
cfadef63
RS
472 ;; Use mark-marker to avoid confusion in transient-mark-mode.
473 (mark-context (if (eq (marker-buffer (mark-marker)) (current-buffer))
474 (vc-position-context (mark-marker))))
475 ;; Make the right thing happen in transient-mark-mode.
ab877583
RM
476 (mark-active nil)
477 ;; We may want to reparse the compilation buffer after revert
478 (reparse (and (boundp 'compilation-error-list) ;compile loaded
479 (let ((curbuf (current-buffer)))
480 ;; Construct a list; each elt is nil or a buffer
481 ;; iff that buffer is a compilation output buffer
482 ;; that contains markers into the current buffer.
483 (save-excursion
7ef84cf9
RS
484 (mapcar (function
485 (lambda (buffer)
ab877583
RM
486 (set-buffer buffer)
487 (let ((errors (or
488 compilation-old-error-list
489 compilation-error-list))
490 (buffer-error-marked-p nil))
6fb6ab11 491 (while (and (consp errors)
ab877583 492 (not buffer-error-marked-p))
a1bda481 493 (and (markerp (cdr (car errors)))
e9c8e248
RM
494 (eq buffer
495 (marker-buffer
a1bda481 496 (cdr (car errors))))
e9c8e248 497 (setq buffer-error-marked-p t))
ab877583 498 (setq errors (cdr errors)))
7ef84cf9 499 (if buffer-error-marked-p buffer))))
ab877583 500 (buffer-list)))))))
c8de1d91
AS
501 (list point-context mark-context reparse)))
502
503(defun vc-restore-buffer-context (context)
504 ;; Restore point/mark, and reparse any affected compilation buffers.
505 ;; CONTEXT is that which vc-buffer-context returns.
506 (let ((point-context (nth 0 context))
507 (mark-context (nth 1 context))
508 (reparse (nth 2 context)))
ab877583
RM
509 ;; Reparse affected compilation buffers.
510 (while reparse
511 (if (car reparse)
512 (save-excursion
513 (set-buffer (car reparse))
514 (let ((compilation-last-buffer (current-buffer)) ;select buffer
515 ;; Record the position in the compilation buffer of
516 ;; the last error next-error went to.
517 (error-pos (marker-position
518 (car (car-safe compilation-error-list)))))
519 ;; Reparse the error messages as far as they were parsed before.
520 (compile-reinitialize-errors '(4) compilation-parsing-end)
521 ;; Move the pointer up to find the error we were at before
522 ;; reparsing. Now next-error should properly go to the next one.
523 (while (and compilation-error-list
27f2f10b 524 (/= error-pos (car (car compilation-error-list))))
ab877583
RM
525 (setq compilation-error-list (cdr compilation-error-list))))))
526 (setq reparse (cdr reparse)))
e1f297e6 527
7b4f934d 528 ;; Restore point and mark
c4ae7096
JB
529 (let ((new-point (vc-find-position-by-context point-context)))
530 (if new-point (goto-char new-point)))
531 (if mark-context
532 (let ((new-mark (vc-find-position-by-context mark-context)))
533 (if new-mark (set-mark new-mark))))))
534
c8de1d91
AS
535(defun vc-revert-buffer1 (&optional arg no-confirm)
536 ;; Revert buffer, try to keep point and mark where user expects them in spite
537 ;; of changes because of expanded version-control key words.
538 ;; This is quite important since otherwise typeahead won't work as expected.
539 (interactive "P")
540 (widen)
541 (let ((context (vc-buffer-context)))
542 (revert-buffer arg no-confirm)
543 (vc-restore-buffer-context context)))
544
594722a8 545
97d3f950 546(defun vc-buffer-sync (&optional not-urgent)
594722a8 547 ;; Make sure the current buffer and its working file are in sync
97d3f950 548 ;; NOT-URGENT means it is ok to continue if the user says not to save.
bbf97570 549 (if (buffer-modified-p)
97d3f950
RS
550 (if (or vc-suppress-confirm
551 (y-or-n-p (format "Buffer %s modified; save it? " (buffer-name))))
552 (save-buffer)
553 (if not-urgent
554 nil
555 (error "Aborted")))))
556
594722a8 557
9a51ed3a 558(defun vc-workfile-unchanged-p (file &optional want-differences-if-changed)
594722a8
ER
559 ;; Has the given workfile changed since last checkout?
560 (let ((checkout-time (vc-file-getprop file 'vc-checkout-time))
561 (lastmod (nth 5 (file-attributes file))))
9a51ed3a
PE
562 (or (equal checkout-time lastmod)
563 (and (or (not checkout-time) want-differences-if-changed)
564 (let ((unchanged (zerop (vc-backend-diff file nil nil
c6d4f628 565 (not want-differences-if-changed)))))
9a51ed3a
PE
566 ;; 0 stands for an unknown time; it can't match any mod time.
567 (vc-file-setprop file 'vc-checkout-time (if unchanged lastmod 0))
568 unchanged)))))
594722a8 569
e1f297e6
ER
570(defun vc-next-action-on-file (file verbose &optional comment)
571 ;;; If comment is specified, it will be used as an admin or checkin comment.
80688f5c 572 (let ((vc-file (vc-name file))
f3c61d82 573 (vc-type (vc-backend file))
8dd71345 574 owner version buffer)
e1f297e6
ER
575 (cond
576
577 ;; if there is no master file corresponding, create one
578 ((not vc-file)
632e9525
RS
579 (vc-register verbose comment)
580 (if vc-initial-comment
581 (setq vc-log-after-operation-hook
582 'vc-checkout-writable-buffer-hook)
583 (vc-checkout-writable-buffer file)))
e1f297e6 584
61dee1e7
AS
585 ;; CVS: changes to the master file need to be
586 ;; merged back into the working file
587 ((and (eq vc-type 'CVS)
588 (or (eq (vc-cvs-status file) 'needs-checkout)
589 (eq (vc-cvs-status file) 'needs-merge)))
8dd71345
AS
590 (if (or vc-dired-mode
591 (yes-or-no-p
592 (format "%s is not up-to-date. Merge in changes now? "
593 (buffer-name))))
61dee1e7 594 (progn
8dd71345
AS
595 (if vc-dired-mode
596 (and (setq buffer (get-file-buffer file))
597 (buffer-modified-p buffer)
598 (switch-to-buffer-other-window buffer)
599 (vc-buffer-sync t))
600 (setq buffer (current-buffer))
601 (vc-buffer-sync t))
602 (if (and buffer (buffer-modified-p buffer)
61dee1e7 603 (not (yes-or-no-p
8dd71345
AS
604 (format
605 "Buffer %s modified; merge file on disc anyhow? "
606 (buffer-name buffer)))))
61dee1e7
AS
607 (error "Merge aborted"))
608 (if (not (zerop (vc-backend-merge-news file)))
609 ;; Overlaps detected - what now? Should use some
610 ;; fancy RCS conflict resolving package, or maybe
611 ;; emerge, but for now, simply warn the user with a
612 ;; message.
613 (message "Conflicts detected!"))
8dd71345
AS
614 (and buffer
615 (vc-resynch-buffer file t (not (buffer-modified-p buffer)))))
61dee1e7
AS
616 (error "%s needs update" (buffer-name))))
617
e1f297e6 618 ;; if there is no lock on the file, assert one and get it
61dee1e7 619 ((not (setq owner (vc-locking-user file)))
bbf97570 620 (if (and vc-checkout-carefully
9a51ed3a 621 (not (vc-workfile-unchanged-p file t)))
bbf97570 622 (if (save-window-excursion
6aa13729 623 (pop-to-buffer "*vc-diff*")
bbf97570
RS
624 (goto-char (point-min))
625 (insert-string (format "Changes to %s since last lock:\n\n"
626 file))
627 (not (beep))
628 (yes-or-no-p
629 (concat "File has unlocked changes, "
630 "claim lock retaining changes? ")))
631 (progn (vc-backend-steal file)
632 (vc-mode-line file))
633 (if (not (yes-or-no-p "Revert to checked-in version, instead? "))
634 (error "Checkout aborted.")
635 (vc-revert-buffer1 t t)
636 (vc-checkout-writable-buffer file))
637 )
c6d4f628
RS
638 (if verbose
639 (if (not (eq vc-type 'SCCS))
e163b283
AS
640 (vc-checkout file nil
641 (read-string "Branch or version to move to: "))
c6d4f628 642 (error "Sorry, this is not implemented for SCCS."))
9341ff29
AS
643 (if (vc-latest-on-branch-p file)
644 (vc-checkout-writable-buffer file)
645 (if (yes-or-no-p
646 "This is not the latest version. Really lock it? ")
647 (vc-checkout-writable-buffer file)
648 (if (yes-or-no-p "Lock the latest version instead? ")
649 (vc-checkout-writable-buffer file
650 (vc-branch-part (vc-workfile-version file))))))
651 )))
e1f297e6
ER
652
653 ;; a checked-out version exists, but the user may not own the lock
61dee1e7 654 ((and (not (eq vc-type 'CVS))
80688f5c 655 (not (string-equal owner (user-login-name))))
e1f297e6 656 (if comment
590cc449 657 (error "Sorry, you can't steal the lock on %s this way" file))
b0c9bc8c
AS
658 (and (eq vc-type 'RCS)
659 (not (vc-backend-release-p 'RCS "5.6.2"))
660 (error "File is locked by %s." owner))
e1f297e6
ER
661 (vc-steal-lock
662 file
c6d4f628
RS
663 (if verbose (read-string "Version to steal: ")
664 (vc-workfile-version file))
e1f297e6 665 owner))
80688f5c 666
c6d4f628 667 ;; OK, user owns the lock on the file
8c0aaf40 668 (t
b0c9bc8c
AS
669 (if vc-dired-mode
670 (find-file-other-window file)
671 (find-file file))
e1f297e6
ER
672
673 ;; give luser a chance to save before checking in.
674 (vc-buffer-sync)
675
676 ;; Revert if file is unchanged and buffer is too.
677 ;; If buffer is modified, that means the user just said no
678 ;; to saving it; in that case, don't revert,
679 ;; because the user might intend to save
680 ;; after finishing the log entry.
80688f5c 681 (if (and (vc-workfile-unchanged-p file)
e1f297e6 682 (not (buffer-modified-p)))
c6d4f628
RS
683 ;; DO NOT revert the file without asking the user!
684 (cond
685 ((yes-or-no-p "Revert to master version? ")
686 (vc-backend-revert file)
687 (vc-resynch-window file t t)))
e1f297e6
ER
688
689 ;; user may want to set nonstandard parameters
690 (if verbose
691 (setq version (read-string "New version level: ")))
692
693 ;; OK, let's do the checkin
694 (vc-checkin file version comment)
8c0aaf40 695 )))))
e1f297e6
ER
696
697(defun vc-next-action-dired (file rev comment)
b0c9bc8c
AS
698 ;; Do a vc-next-action-on-file on all the marked files, possibly
699 ;; passing on the log comment we've just entered.
700 (let ((configuration (current-window-configuration))
8dd71345
AS
701 (dired-buffer (current-buffer))
702 (dired-dir default-directory))
632e9525 703 (dired-map-over-marks
b0c9bc8c
AS
704 (let ((file (dired-get-filename)) p)
705 (message "Processing %s..." file)
8dd71345
AS
706 ;; Adjust the default directory so that checkouts
707 ;; go to the right place.
708 (setq default-directory (file-name-directory file))
b0c9bc8c
AS
709 (vc-next-action-on-file file nil comment)
710 (set-buffer dired-buffer)
8dd71345 711 (setq default-directory dired-dir)
b0c9bc8c
AS
712 (vc-dired-update-line file)
713 (set-window-configuration configuration)
714 (message "Processing %s...done" file))
715 nil t)))
e1f297e6 716
637a8ae9 717;; Here's the major entry point.
594722a8 718
637a8ae9 719;;;###autoload
594722a8
ER
720(defun vc-next-action (verbose)
721 "Do the next logical checkin or checkout operation on the current file.
c6d4f628
RS
722 If you call this from within a VC dired buffer with no files marked,
723it will operate on the file in the current line.
724 If you call this from within a VC dired buffer, and one or more
725files are marked, it will accept a log message and then operate on
726each one. The log message will be used as a comment for any register
727or checkin operations, but ignored when doing checkouts. Attempted
728lock steals will raise an error.
729 A prefix argument lets you specify the version number to use.
80688f5c
RS
730
731For RCS and SCCS files:
594722a8 732 If the file is not already registered, this registers it for version
34291cd2 733control and then retrieves a writable, locked copy for editing.
594722a8 734 If the file is registered and not locked by anyone, this checks out
34291cd2 735a writable and locked file ready for editing.
594722a8
ER
736 If the file is checked out and locked by the calling user, this
737first checks to see if the file has changed since checkout. If not,
738it performs a revert.
e1f297e6
ER
739 If the file has been changed, this pops up a buffer for entry
740of a log message; when the message has been entered, it checks in the
594722a8 741resulting changes along with the log message as change commentary. If
34291cd2 742the variable `vc-keep-workfiles' is non-nil (which is its default), a
594722a8
ER
743read-only copy of the changed file is left in place afterwards.
744 If the file is registered and locked by someone else, you are given
e1f297e6 745the option to steal the lock.
80688f5c
RS
746
747For CVS files:
748 If the file is not already registered, this registers it for version
749control. This does a \"cvs add\", but no \"cvs commit\".
750 If the file is added but not committed, it is committed.
80688f5c
RS
751 If your working file is changed, but the repository file is
752unchanged, this pops up a buffer for entry of a log message; when the
753message has been entered, it checks in the resulting changes along
754with the logmessage as change commentary. A writable file is retained.
755 If the repository file is changed, you are asked if you want to
c6d4f628 756merge in the changes into your working copy."
bbf97570 757
594722a8 758 (interactive "P")
8c0aaf40
ER
759 (catch 'nogo
760 (if vc-dired-mode
761 (let ((files (dired-get-marked-files)))
8dd71345
AS
762 (if (string= ""
763 (mapconcat
b0c9bc8c
AS
764 (function (lambda (f)
765 (if (eq (vc-backend f) 'CVS)
8dd71345
AS
766 (if (or (eq (vc-cvs-status f) 'locally-modified)
767 (eq (vc-cvs-status f) 'locally-added))
b0c9bc8c
AS
768 "@" "")
769 (if (vc-locking-user f) "@" ""))))
770 files ""))
771 (vc-next-action-dired nil nil "dummy")
772 (vc-start-entry nil nil nil
773 "Enter a change comment for the marked files."
774 'vc-next-action-dired))
8dd71345 775 (throw 'nogo nil)))
e1f297e6 776 (while vc-parent-buffer
1a2f456b 777 (pop-to-buffer vc-parent-buffer))
e1f297e6
ER
778 (if buffer-file-name
779 (vc-next-action-on-file buffer-file-name verbose)
7ef84cf9 780 (vc-registration-error nil))))
594722a8
ER
781
782;;; These functions help the vc-next-action entry point
783
c6d4f628 784(defun vc-checkout-writable-buffer (&optional file rev)
34291cd2 785 "Retrieve a writable copy of the latest version of the current buffer's file."
c6d4f628 786 (vc-checkout (or file (buffer-file-name)) t rev)
02da6253
PE
787 )
788
637a8ae9 789;;;###autoload
e1f297e6 790(defun vc-register (&optional override comment)
594722a8
ER
791 "Register the current file into your version-control system."
792 (interactive "P")
f1b82fc8
KH
793 (or buffer-file-name
794 (error "No visited file"))
e837a82f
RS
795 (let ((master (vc-name buffer-file-name)))
796 (and master (file-exists-p master)
797 (error "This file is already registered"))
798 (and master
799 (not (y-or-n-p "Previous master file has vanished. Make a new one? "))
800 (error "This file is already registered")))
02da6253
PE
801 ;; Watch out for new buffers of size 0: the corresponding file
802 ;; does not exist yet, even though buffer-modified-p is nil.
803 (if (and (not (buffer-modified-p))
804 (zerop (buffer-size))
805 (not (file-exists-p buffer-file-name)))
806 (set-buffer-modified-p t))
594722a8 807 (vc-buffer-sync)
993a1a44
RS
808 (cond ((not vc-make-backup-files)
809 ;; inhibit backup for this buffer
810 (make-local-variable 'backup-inhibited)
811 (setq backup-inhibited t)))
594722a8
ER
812 (vc-admin
813 buffer-file-name
e1f297e6
ER
814 (and override
815 (read-string
816 (format "Initial version level for %s: " buffer-file-name))))
594722a8
ER
817 )
818
624b4662 819(defun vc-resynch-window (file &optional keep noquery)
594722a8
ER
820 ;; If the given file is in the current buffer,
821 ;; either revert on it so we see expanded keyworks,
822 ;; or unvisit it (depending on vc-keep-workfiles)
624b4662
RS
823 ;; NOQUERY if non-nil inhibits confirmation for reverting.
824 ;; NOQUERY should be t *only* if it is known the only difference
825 ;; between the buffer and the file is due to RCS rather than user editing!
594722a8
ER
826 (and (string= buffer-file-name file)
827 (if keep
828 (progn
88a2ffaf
RS
829 ;; temporarily remove vc-find-file-hook, so that
830 ;; we don't lose the properties
831 (remove-hook 'find-file-hooks 'vc-find-file-hook)
1ab31687 832 (vc-revert-buffer1 t noquery)
88a2ffaf 833 (add-hook 'find-file-hooks 'vc-find-file-hook)
594722a8 834 (vc-mode-line buffer-file-name))
88a2ffaf 835 (kill-buffer (current-buffer)))))
594722a8 836
503b5c85 837(defun vc-resynch-buffer (file &optional keep noquery)
b0c9bc8c 838 ;; if FILE is currently visited, resynch its buffer
503b5c85
RS
839 (let ((buffer (get-file-buffer file)))
840 (if buffer
841 (save-excursion
842 (set-buffer buffer)
843 (vc-resynch-window file keep noquery)))))
844
b965445f 845(defun vc-start-entry (file rev comment msg action &optional after-hook)
e1f297e6
ER
846 ;; Accept a comment for an operation on FILE revision REV. If COMMENT
847 ;; is nil, pop up a VC-log buffer, emit MSG, and set the
848 ;; action on close to ACTION; otherwise, do action immediately.
cdaf7a1a 849 ;; Remember the file's buffer in vc-parent-buffer (current one if no file).
b965445f 850 ;; AFTER-HOOK specifies the local value for vc-log-operation-hook.
e1f297e6
ER
851 (let ((parent (if file (find-file-noselect file) (current-buffer))))
852 (if comment
853 (set-buffer (get-buffer-create "*VC-log*"))
854 (pop-to-buffer (get-buffer-create "*VC-log*")))
8c0aaf40
ER
855 (set (make-local-variable 'vc-parent-buffer) parent)
856 (set (make-local-variable 'vc-parent-buffer-name)
857 (concat " from " (buffer-name vc-parent-buffer)))
7e869659 858 (if file (vc-mode-line file))
e1f297e6 859 (vc-log-mode)
b965445f
RS
860 (make-local-variable 'vc-log-after-operation-hook)
861 (if after-hook
862 (setq vc-log-after-operation-hook after-hook))
e1f297e6
ER
863 (setq vc-log-operation action)
864 (setq vc-log-file file)
865 (setq vc-log-version rev)
866 (if comment
867 (progn
868 (erase-buffer)
8c0aaf40
ER
869 (if (eq comment t)
870 (vc-finish-logentry t)
871 (insert comment)
872 (vc-finish-logentry nil)))
e1f297e6 873 (message "%s Type C-c C-c when done." msg))))
594722a8 874
e1f297e6 875(defun vc-admin (file rev &optional comment)
624b4662 876 "Check a file into your version-control system.
594722a8 877FILE is the unmodified name of the file. REV should be the base version
e1f297e6 878level to check it in under. COMMENT, if specified, is the checkin comment."
b965445f
RS
879 (vc-start-entry file rev
880 (or comment (not vc-initial-comment))
881 "Enter initial comment." 'vc-backend-admin
6bcb1d4e 882 nil))
e1f297e6 883
c6d4f628 884(defun vc-checkout (file &optional writable rev)
e1f297e6
ER
885 "Retrieve a copy of the latest version of the given file."
886 ;; If ftp is on this system and the name matches the ange-ftp format
887 ;; for a remote file, the user is trying something that won't work.
888 (if (and (string-match "^/[^/:]+:" file) (vc-find-binary "ftp"))
889 (error "Sorry, you can't check out files over FTP"))
c6d4f628 890 (vc-backend-checkout file writable rev)
b0c9bc8c 891 (vc-resynch-buffer file t t))
594722a8
ER
892
893(defun vc-steal-lock (file rev &optional owner)
894 "Steal the lock on the current workfile."
29fc1ce9
RS
895 (let (file-description)
896 (if (not owner)
897 (setq owner (vc-locking-user file)))
898 (if rev
899 (setq file-description (format "%s:%s" file rev))
900 (setq file-description file))
901 (if (not (y-or-n-p (format "Take the lock on %s from %s? "
902 file-description owner)))
903 (error "Steal cancelled"))
904 (pop-to-buffer (get-buffer-create "*VC-mail*"))
905 (setq default-directory (expand-file-name "~/"))
906 (auto-save-mode auto-save-default)
907 (mail-mode)
908 (erase-buffer)
909 (mail-setup owner (format "Stolen lock on %s" file-description) nil nil nil
3e3da61f 910 (list (list 'vc-finish-steal file rev)))
29fc1ce9
RS
911 (goto-char (point-max))
912 (insert
913 (format "I stole the lock on %s, " file-description)
914 (current-time-string)
915 ".\n")
916 (message "Please explain why you stole the lock. Type C-c C-c when done.")))
594722a8 917
ad014629 918;; This is called when the notification has been sent.
594722a8 919(defun vc-finish-steal (file version)
594722a8 920 (vc-backend-steal file version)
3e3da61f
RS
921 (if (get-file-buffer file)
922 (save-excursion
6242bee4 923 (set-buffer (get-file-buffer file))
3e3da61f 924 (vc-resynch-window file t t))))
594722a8 925
594722a8
ER
926(defun vc-checkin (file &optional rev comment)
927 "Check in the file specified by FILE.
928The optional argument REV may be a string specifying the new version level
67242a23 929\(if nil increment the current level). The file is either retained with write
34291cd2 930permissions zeroed, or deleted (according to the value of `vc-keep-workfiles').
80688f5c 931If the back-end is CVS, a writable workfile is always kept.
594722a8
ER
932COMMENT is a comment string; if omitted, a buffer is
933popped up to accept a comment."
61446fe7 934 (vc-start-entry file rev comment
b965445f
RS
935 "Enter a change comment." 'vc-backend-checkin
936 'vc-checkin-hook))
594722a8 937
1a2f456b
ER
938;;; Here is a checkin hook that may prove useful to sites using the
939;;; ChangeLog facility supported by Emacs.
3b4dd9a9
RM
940(defun vc-comment-to-change-log (&optional whoami file-name)
941 "Enter last VC comment into change log file for current buffer's file.
942Optional arg (interactive prefix) non-nil means prompt for user name and site.
943Second arg is file name of change log. \
944If nil, uses `change-log-default-name'."
43cea1ab
RM
945 (interactive (if current-prefix-arg
946 (list current-prefix-arg
947 (prompt-for-change-log-name))))
41208291
KH
948 ;; Make sure the defvar for add-log-current-defun-function has been executed
949 ;; before binding it.
950 (require 'add-log)
3b4dd9a9
RM
951 (let (;; Extract the comment first so we get any error before doing anything.
952 (comment (ring-ref vc-comment-ring 0))
43cea1ab 953 ;; Don't let add-change-log-entry insert a defun name.
3b4dd9a9
RM
954 (add-log-current-defun-function 'ignore)
955 end)
956 ;; Call add-log to do half the work.
43cea1ab 957 (add-change-log-entry whoami file-name t t)
3b4dd9a9
RM
958 ;; Insert the VC comment, leaving point before it.
959 (setq end (save-excursion (insert comment) (point-marker)))
960 (if (looking-at "\\s *\\s(")
961 ;; It starts with an open-paren, as in "(foo): Frobbed."
43cea1ab 962 ;; So remove the ": " add-log inserted.
3b4dd9a9
RM
963 (delete-char -2))
964 ;; Canonicalize the white space between the file name and comment.
965 (just-one-space)
966 ;; Indent rest of the text the same way add-log indented the first line.
967 (let ((indentation (current-indentation)))
968 (save-excursion
969 (while (< (point) end)
970 (forward-line 1)
971 (indent-to indentation))
c124b1b4 972 (setq end (point))))
3b4dd9a9 973 ;; Fill the inserted text, preserving open-parens at bol.
6b60c5d1
BG
974 (let ((paragraph-separate (concat paragraph-separate "\\|\\s *\\s("))
975 (paragraph-start (concat paragraph-start "\\|\\s *\\s(")))
43cea1ab 976 (beginning-of-line)
c124b1b4
RM
977 (fill-region (point) end))
978 ;; Canonicalize the white space at the end of the entry so it is
979 ;; separated from the next entry by a single blank line.
980 (skip-syntax-forward " " end)
981 (delete-char (- (skip-syntax-backward " ")))
982 (or (eobp) (looking-at "\n\n")
983 (insert "\n"))))
3b4dd9a9 984
1a2f456b 985
8c0aaf40 986(defun vc-finish-logentry (&optional nocomment)
594722a8
ER
987 "Complete the operation implied by the current log entry."
988 (interactive)
8c0aaf40
ER
989 ;; Check and record the comment, if any.
990 (if (not nocomment)
991 (progn
992 (goto-char (point-max))
993 (if (not (bolp))
994 (newline))
995 ;; Comment too long?
996 (vc-backend-logentry-check vc-log-file)
997 ;; Record the comment in the comment ring
998 (if (null vc-comment-ring)
999 (setq vc-comment-ring (make-ring vc-maximum-comment-ring-size)))
1000 (ring-insert vc-comment-ring (buffer-string))
1001 ))
b2396d1f 1002 ;; Sync parent buffer in case the user modified it while editing the comment.
cdaf7a1a 1003 ;; But not if it is a vc-dired buffer.
b2396d1f 1004 (save-excursion
cdaf7a1a
RS
1005 (set-buffer vc-parent-buffer)
1006 (or vc-dired-mode
1007 (vc-buffer-sync)))
61dee1e7
AS
1008 (if (not vc-log-operation) (error "No log operation is pending"))
1009 ;; save the parameters held in buffer-local variables
1010 (let ((log-operation vc-log-operation)
1011 (log-file vc-log-file)
1012 (log-version vc-log-version)
1013 (log-entry (buffer-string))
1014 (after-hook vc-log-after-operation-hook))
e2bef5c3
RS
1015 ;; Return to "parent" buffer of this checkin and remove checkin window
1016 (pop-to-buffer vc-parent-buffer)
1017 (let ((logbuf (get-buffer "*VC-log*")))
1018 (delete-windows-on logbuf)
1019 (kill-buffer logbuf))
61dee1e7
AS
1020 ;; OK, do it to it
1021 (save-excursion
1022 (funcall log-operation
1023 log-file
1024 log-version
1025 log-entry))
e2bef5c3
RS
1026 ;; Now make sure we see the expanded headers
1027 (if buffer-file-name
e1f297e6 1028 (vc-resynch-window buffer-file-name vc-keep-workfiles t))
e2bef5c3 1029 (run-hooks after-hook)))
594722a8
ER
1030
1031;; Code for access to the comment ring
1032
8c0aaf40
ER
1033(defun vc-previous-comment (arg)
1034 "Cycle backwards through comment history."
1035 (interactive "*p")
1036 (let ((len (ring-length vc-comment-ring)))
1037 (cond ((<= len 0)
1038 (message "Empty comment ring")
1039 (ding))
1040 (t
1041 (erase-buffer)
1042 ;; Initialize the index on the first use of this command
1043 ;; so that the first M-p gets index 0, and the first M-n gets
1044 ;; index -1.
1045 (if (null vc-comment-ring-index)
1046 (setq vc-comment-ring-index
1047 (if (> arg 0) -1
1048 (if (< arg 0) 1 0))))
1049 (setq vc-comment-ring-index
c6bfcd12 1050 (mod (+ vc-comment-ring-index arg) len))
8c0aaf40
ER
1051 (message "%d" (1+ vc-comment-ring-index))
1052 (insert (ring-ref vc-comment-ring vc-comment-ring-index))))))
1053
1054(defun vc-next-comment (arg)
1055 "Cycle forwards through comment history."
1056 (interactive "*p")
1057 (vc-previous-comment (- arg)))
1058
1059(defun vc-comment-search-reverse (str)
1060 "Searches backwards through comment history for substring match."
1061 (interactive "sComment substring: ")
1062 (if (string= str "")
1063 (setq str vc-last-comment-match)
1064 (setq vc-last-comment-match str))
1065 (if (null vc-comment-ring-index)
1066 (setq vc-comment-ring-index -1))
1067 (let ((str (regexp-quote str))
1068 (len (ring-length vc-comment-ring))
1069 (n (1+ vc-comment-ring-index)))
1070 (while (and (< n len) (not (string-match str (ring-ref vc-comment-ring n))))
1071 (setq n (+ n 1)))
1072 (cond ((< n len)
1073 (vc-previous-comment (- n vc-comment-ring-index)))
1074 (t (error "Not found")))))
1075
1076(defun vc-comment-search-forward (str)
1077 "Searches forwards through comment history for substring match."
1078 (interactive "sComment substring: ")
1079 (if (string= str "")
1080 (setq str vc-last-comment-match)
1081 (setq vc-last-comment-match str))
1082 (if (null vc-comment-ring-index)
1083 (setq vc-comment-ring-index 0))
1084 (let ((str (regexp-quote str))
1085 (len (ring-length vc-comment-ring))
1086 (n vc-comment-ring-index))
1087 (while (and (>= n 0) (not (string-match str (ring-ref vc-comment-ring n))))
1088 (setq n (- n 1)))
1089 (cond ((>= n 0)
1090 (vc-next-comment (- n vc-comment-ring-index)))
1091 (t (error "Not found")))))
594722a8
ER
1092
1093;; Additional entry points for examining version histories
1094
637a8ae9 1095;;;###autoload
97d3f950 1096(defun vc-diff (historic &optional not-urgent)
e8ee1ccf
RS
1097 "Display diffs between file versions.
1098Normally this compares the current file and buffer with the most recent
1099checked in version of that file. This uses no arguments.
1100With a prefix argument, it reads the file name to use
1101and two version designators specifying which versions to compare."
594722a8 1102 (interactive "P")
e1f297e6
ER
1103 (if vc-dired-mode
1104 (set-buffer (find-file-noselect (dired-get-filename))))
8ac8c82f 1105 (while vc-parent-buffer
1a2f456b 1106 (pop-to-buffer vc-parent-buffer))
594722a8
ER
1107 (if historic
1108 (call-interactively 'vc-version-diff)
8c0aaf40 1109 (if (or (null buffer-file-name) (null (vc-name buffer-file-name)))
064726ac
JB
1110 (error
1111 "There is no version-control master associated with this buffer"))
02da6253 1112 (let ((file buffer-file-name)
594722a8 1113 unchanged)
7ef84cf9
RS
1114 (or (and file (vc-name file))
1115 (vc-registration-error file))
97d3f950 1116 (vc-buffer-sync not-urgent)
594722a8
ER
1117 (setq unchanged (vc-workfile-unchanged-p buffer-file-name))
1118 (if unchanged
02da6253 1119 (message "No changes to %s since latest version." file)
9a51ed3a 1120 (vc-backend-diff file)
8c0aaf40
ER
1121 ;; Ideally, we'd like at this point to parse the diff so that
1122 ;; the buffer effectively goes into compilation mode and we
1123 ;; can visit the old and new change locations via next-error.
1124 ;; Unfortunately, this is just too painful to do. The basic
1125 ;; problem is that the `old' file doesn't exist to be
1126 ;; visited. This plays hell with numerous assumptions in
1127 ;; the diff.el and compile.el machinery.
6aa13729 1128 (pop-to-buffer "*vc-diff*")
632e9525 1129 (setq default-directory (file-name-directory file))
b246f571
RS
1130 (if (= 0 (buffer-size))
1131 (progn
1132 (setq unchanged t)
1133 (message "No changes to %s since latest version." file))
4c2d8cf9 1134 (goto-char (point-min))
064726ac
JB
1135 (shrink-window-if-larger-than-buffer)))
1136 (not unchanged))))
594722a8
ER
1137
1138(defun vc-version-diff (file rel1 rel2)
1139 "For FILE, report diffs between two stored versions REL1 and REL2 of it.
1140If FILE is a directory, generate diffs between versions for all registered
1141files in or below it."
3234e2a3 1142 (interactive "FFile or directory to diff: \nsOlder version: \nsNewer version: ")
594722a8
ER
1143 (if (string-equal rel1 "") (setq rel1 nil))
1144 (if (string-equal rel2 "") (setq rel2 nil))
1145 (if (file-directory-p file)
1a2f456b 1146 (let ((camefrom (current-buffer)))
594722a8 1147 (set-buffer (get-buffer-create "*vc-status*"))
8c0aaf40
ER
1148 (set (make-local-variable 'vc-parent-buffer) camefrom)
1149 (set (make-local-variable 'vc-parent-buffer-name)
1150 (concat " from " (buffer-name camefrom)))
594722a8 1151 (erase-buffer)
3234e2a3
ER
1152 (insert "Diffs between "
1153 (or rel1 "last version checked in")
1154 " and "
1155 (or rel2 "current workfile(s)")
1156 ":\n\n")
6aa13729 1157 (set-buffer (get-buffer-create "*vc-diff*"))
e1f297e6 1158 (cd file)
594722a8 1159 (vc-file-tree-walk
2f119435 1160 default-directory
594722a8 1161 (function (lambda (f)
a9a59766 1162 (message "Looking at %s" f)
594722a8 1163 (and
3234e2a3
ER
1164 (not (file-directory-p f))
1165 (vc-registered f)
02da6253
PE
1166 (vc-backend-diff f rel1 rel2)
1167 (append-to-buffer "*vc-status*" (point-min) (point-max)))
1168 )))
594722a8
ER
1169 (pop-to-buffer "*vc-status*")
1170 (insert "\nEnd of diffs.\n")
1171 (goto-char (point-min))
1172 (set-buffer-modified-p nil)
1173 )
36bed8bc
RS
1174 (if (zerop (vc-backend-diff file rel1 rel2))
1175 (message "No changes to %s between %s and %s." file rel1 rel2)
6aa13729 1176 (pop-to-buffer "*vc-diff*"))))
594722a8 1177
f1818994
PE
1178;;;###autoload
1179(defun vc-version-other-window (rev)
1180 "Visit version REV of the current buffer in another window.
1181If the current buffer is named `F', the version is named `F.~REV~'.
1182If `F.~REV~' already exists, it is used instead of being re-created."
1183 (interactive "sVersion to visit (default is latest version): ")
1184 (if vc-dired-mode
1185 (set-buffer (find-file-noselect (dired-get-filename))))
1186 (while vc-parent-buffer
1187 (pop-to-buffer vc-parent-buffer))
1188 (if (and buffer-file-name (vc-name buffer-file-name))
1189 (let* ((version (if (string-equal rev "")
1190 (vc-latest-version buffer-file-name)
1191 rev))
1192 (filename (concat buffer-file-name ".~" version "~")))
1193 (or (file-exists-p filename)
1194 (vc-backend-checkout buffer-file-name nil version filename))
1195 (find-file-other-window filename))
1196 (vc-registration-error buffer-file-name)))
1197
594722a8
ER
1198;; Header-insertion code
1199
637a8ae9 1200;;;###autoload
594722a8
ER
1201(defun vc-insert-headers ()
1202 "Insert headers in a file for use with your version-control system.
1203Headers desired are inserted at the start of the buffer, and are pulled from
34291cd2 1204the variable `vc-header-alist'."
594722a8 1205 (interactive)
e1f297e6
ER
1206 (if vc-dired-mode
1207 (find-file-other-window (dired-get-filename)))
8ac8c82f 1208 (while vc-parent-buffer
1a2f456b 1209 (pop-to-buffer vc-parent-buffer))
594722a8
ER
1210 (save-excursion
1211 (save-restriction
1212 (widen)
1213 (if (or (not (vc-check-headers))
820bde8d 1214 (y-or-n-p "Version headers already exist. Insert another set? "))
594722a8
ER
1215 (progn
1216 (let* ((delims (cdr (assq major-mode vc-comment-alist)))
1217 (comment-start-vc (or (car delims) comment-start "#"))
1218 (comment-end-vc (or (car (cdr delims)) comment-end ""))
f3c61d82 1219 (hdstrings (cdr (assoc (vc-backend (buffer-file-name)) vc-header-alist))))
594722a8
ER
1220 (mapcar (function (lambda (s)
1221 (insert comment-start-vc "\t" s "\t"
1222 comment-end-vc "\n")))
1223 hdstrings)
1224 (if vc-static-header-alist
1225 (mapcar (function (lambda (f)
1226 (if (string-match (car f) buffer-file-name)
1227 (insert (format (cdr f) (car hdstrings))))))
1228 vc-static-header-alist))
1229 )
1230 )))))
1231
c8de1d91
AS
1232(defun vc-clear-headers ()
1233 ;; Clear all version headers in the current buffer, i.e. reset them
1234 ;; to the nonexpanded form. Only implemented for RCS, yet.
1235 ;; Don't lose point and mark during this.
1236 (let ((context (vc-buffer-context)))
1237 (goto-char (point-min))
1238 (while (re-search-forward "\\$\\([A-Za-z]+\\): [^\\$]+\\$" nil t)
1239 (replace-match "$\\1$"))
1240 (vc-restore-buffer-context context)))
1241
2f119435 1242;; The VC directory major mode. Coopt Dired for this.
e1f297e6
ER
1243;; All VC commands get mapped into logical equivalents.
1244
2f119435
AS
1245(define-derived-mode vc-dired-mode dired-mode "Dired under VC"
1246 "The major mode used in VC directory buffers. It is derived from Dired.
e1f297e6 1247All Dired commands operate normally. Users currently locking listed files
ee7e9c88 1248are listed in place of the file's owner and group.
e1f297e6
ER
1249Keystrokes bound to VC commands will execute as though they had been called
1250on a buffer attached to the file named in the current Dired buffer line."
2f119435
AS
1251 (setq vc-dired-mode t))
1252
1253(define-key vc-dired-mode-map "\C-xv" vc-prefix-map)
1254(define-key vc-dired-mode-map "g" 'vc-dired-update)
1255(define-key vc-dired-mode-map "=" 'vc-diff)
594722a8 1256
b0c9bc8c
AS
1257(defun vc-dired-state-info (file)
1258 ;; Return the string that indicates the version control status
1259 ;; on a VC dired line.
1260 (let ((cvs-state (and (eq (vc-backend file) 'CVS)
1261 (vc-cvs-status file))))
1262 (if cvs-state
1263 (cond ((eq cvs-state 'up-to-date) nil)
1264 ((eq cvs-state 'needs-checkout) "patch")
1265 ((eq cvs-state 'locally-modified) "modified")
1266 ((eq cvs-state 'needs-merge) "merge")
1267 ((eq cvs-state 'unresolved-conflict) "conflict")
1268 ((eq cvs-state 'locally-added) "added"))
1269 (vc-locking-user file))))
1270
8c0aaf40
ER
1271(defun vc-dired-reformat-line (x)
1272 ;; Hack a directory-listing line, plugging in locking-user info in
34291cd2
RS
1273 ;; place of the user and group info. Should have the beneficial
1274 ;; side-effect of shortening the listing line. Each call starts with
8c0aaf40
ER
1275 ;; point immediately following the dired mark area on the line to be
1276 ;; hacked.
1277 ;;
1278 ;; Simplest possible one:
1279 ;; (insert (concat x "\t")))
1280 ;;
1281 ;; This code, like dired, assumes UNIX -l format.
2f119435
AS
1282 (let ((pos (point)) limit perm owner date-and-file)
1283 (end-of-line)
1284 (setq limit (point))
1285 (goto-char pos)
1286 (cond
1287 ((or
1288 (re-search-forward ;; owner and group
1289"\\([drwxlts-]+ \\) *[0-9]+ \\([^ ]+\\) +[^ ]+ +[0-9]+\\( [^ 0-9]+ [0-9 ][0-9] .*\\)"
1290 limit t)
1291 (re-search-forward ;; only owner displayed
1292"\\([drwxlts-]+ \\) *[0-9]+ \\([^ ]+\\) +[0-9]+\\( [^ 0-9]+ [0-9 ][0-9] .*\\)"
1293 limit t))
1294 (setq perm (match-string 1)
1295 owner (match-string 2)
1296 date-and-file (match-string 3)))
1297 ((re-search-forward ;; OS/2 -l format, no links, owner, group
1298"\\([drwxlts-]+ \\) *[0-9]+\\( [^ 0-9]+ [0-9 ][0-9] .*\\)"
1299 limit t)
1300 (setq perm (match-string 1)
1301 date-and-file (match-string 2))))
1302 (if (numberp x) (setq x (or owner (number-to-string x))))
80688f5c 1303 (if x (setq x (concat "(" x ")")))
b0c9bc8c 1304 (let ((rep (substring (concat x " ") 0 10)))
2f119435
AS
1305 (replace-match (concat perm rep date-and-file)))))
1306
b0c9bc8c
AS
1307(defun vc-dired-update-line (file)
1308 ;; Update the vc-dired listing line of file -- it is assumed
8dd71345
AS
1309 ;; that point is already on this line. Don't use dired-do-redisplay
1310 ;; for this, because it cannot handle the way vc-dired deals with
1311 ;; subdirectories.
b0c9bc8c 1312 (beginning-of-line)
8dd71345
AS
1313 (forward-char 2)
1314 (let ((start (point)))
1315 (forward-line 1)
1316 (beginning-of-line)
1317 (delete-region start (point))
1318 (insert-directory file dired-listing-switches)
1319 (forward-line -1)
1320 (end-of-line)
1321 (delete-char (- (length file)))
1322 (insert (substring file (length (expand-file-name default-directory))))
1323 (goto-char start))
b0c9bc8c 1324 (vc-dired-reformat-line (vc-dired-state-info file)))
8c0aaf40 1325
2f119435
AS
1326(defun vc-dired-update (verbose)
1327 (interactive "P")
1328 (vc-directory default-directory verbose))
1329
632e9525
RS
1330;;; Note in Emacs 18 the following defun gets overridden
1331;;; with the symbol 'vc-directory-18. See below.
637a8ae9 1332;;;###autoload
2f119435 1333(defun vc-directory (dirname verbose)
632e9525
RS
1334 "Show version-control status of the current directory and subdirectories.
1335Normally it creates a Dired buffer that lists only the locked files
1336in all these directories. With a prefix argument, it lists all files."
2f119435
AS
1337 (interactive "DDired under VC (directory): \nP")
1338 (setq dirname (expand-file-name dirname))
1339 ;; force a trailing slash
1340 (if (not (eq (elt dirname (1- (length dirname))) ?/))
1341 (setq dirname (concat dirname "/")))
632e9525 1342 (let (nonempty
2f119435 1343 (dl (length dirname))
b0c9bc8c 1344 (filelist nil) (statelist nil)
2f119435 1345 (old-dir default-directory)
632e9525
RS
1346 dired-buf
1347 dired-buf-mod-count)
1348 (vc-file-tree-walk
2f119435 1349 dirname
b0c9bc8c
AS
1350 (function
1351 (lambda (f)
1352 (if (vc-registered f)
1353 (let ((state (vc-dired-state-info f)))
1354 (and (or verbose state)
1355 (setq filelist (cons (substring f dl) filelist))
1356 (setq statelist (cons state statelist))))))))
1357 (save-window-excursion
1358 (save-excursion
2f119435
AS
1359 ;; This uses a semi-documented feature of dired; giving a switch
1360 ;; argument forces the buffer to refresh each time.
1361 (setq dired-buf
1362 (dired-internal-noselect
1363 (cons dirname (nreverse filelist))
1364 dired-listing-switches 'vc-dired-mode))
1365 (setq nonempty (not (eq 0 (length filelist))))))
8dd71345 1366 (switch-to-buffer dired-buf)
8dd71345
AS
1367 ;; Make a few modifications to the header
1368 (setq buffer-read-only nil)
1369 (goto-char (point-min))
1370 (forward-line 1) ;; Skip header line
1371 (let ((start (point))) ;; Erase (but don't remove) the
1372 (end-of-line) ;; "wildcard" line.
1373 (delete-region start (point)))
1374 (beginning-of-line)
594722a8
ER
1375 (if nonempty
1376 (progn
8dd71345 1377 ;; Plug the version information into the individual lines
e1f297e6 1378 (mapcar
7ef84cf9
RS
1379 (function
1380 (lambda (x)
8c0aaf40
ER
1381 (forward-char 2) ;; skip dired's mark area
1382 (vc-dired-reformat-line x)
7ef84cf9 1383 (forward-line 1))) ;; go to next line
b0c9bc8c 1384 (nreverse statelist))
e1f297e6
ER
1385 (setq buffer-read-only t)
1386 (goto-char (point-min))
8dd71345 1387 (dired-next-line 2)
e1f297e6 1388 )
8dd71345
AS
1389 (dired-next-line 1)
1390 (insert " ")
1391 (setq buffer-read-only t)
02da6253 1392 (message "No files are currently %s under %s"
2f119435 1393 (if verbose "registered" "locked") dirname))
594722a8
ER
1394 ))
1395
632e9525
RS
1396;; Emacs 18 version
1397(defun vc-directory-18 (verbose)
1398 "Show version-control status of all files under the current directory."
1399 (interactive "P")
1400 (let (nonempty (dir default-directory))
1401 (save-excursion
1402 (set-buffer (get-buffer-create "*vc-status*"))
1403 (erase-buffer)
1404 (cd dir)
1405 (vc-file-tree-walk
2f119435 1406 default-directory
632e9525
RS
1407 (function (lambda (f)
1408 (if (vc-registered f)
1409 (let ((user (vc-locking-user f)))
1410 (if (or user verbose)
1411 (insert (format
1412 "%s %s\n"
1413 (concat user) f))))))))
1414 (setq nonempty (not (zerop (buffer-size)))))
2f119435 1415
632e9525
RS
1416 (if nonempty
1417 (progn
1418 (pop-to-buffer "*vc-status*" t)
1419 (goto-char (point-min))
1420 (shrink-window-if-larger-than-buffer)))
1421 (message "No files are currently %s under %s"
1422 (if verbose "registered" "locked") default-directory))
1423 )
1424
1425(or (boundp 'minor-mode-map-alist)
1426 (fset 'vc-directory 'vc-directory-18))
e70bdc98 1427
594722a8
ER
1428;; Named-configuration support for SCCS
1429
1430(defun vc-add-triple (name file rev)
1431 (save-excursion
993a1a44
RS
1432 (find-file (expand-file-name
1433 vc-name-assoc-file
1434 (file-name-as-directory
1435 (expand-file-name (vc-backend-subdirectory-name file)
1436 (file-name-directory file)))))
594722a8
ER
1437 (goto-char (point-max))
1438 (insert name "\t:\t" file "\t" rev "\n")
1439 (basic-save-buffer)
1440 (kill-buffer (current-buffer))
1441 ))
1442
1443(defun vc-record-rename (file newname)
1444 (save-excursion
993a1a44
RS
1445 (find-file
1446 (expand-file-name
1447 vc-name-assoc-file
1448 (file-name-as-directory
1449 (expand-file-name (vc-backend-subdirectory-name file)
1450 (file-name-directory file)))))
594722a8 1451 (goto-char (point-min))
7d847440
RS
1452 ;; (replace-regexp (concat ":" (regexp-quote file) "$") (concat ":" newname))
1453 (while (re-search-forward (concat ":" (regexp-quote file) "$") nil t)
1454 (replace-match (concat ":" newname) nil nil))
594722a8
ER
1455 (basic-save-buffer)
1456 (kill-buffer (current-buffer))
1457 ))
1458
1459(defun vc-lookup-triple (file name)
7b4f934d
ER
1460 ;; Return the numeric version corresponding to a named snapshot of file
1461 ;; If name is nil or a version number string it's just passed through
47ca02a6 1462 (cond ((null name) name)
7b4f934d
ER
1463 ((let ((firstchar (aref name 0)))
1464 (and (>= firstchar ?0) (<= firstchar ?9)))
1465 name)
1466 (t
b7011339
RS
1467 (save-excursion
1468 (set-buffer (get-buffer-create "*vc-info*"))
993a1a44
RS
1469 (vc-insert-file
1470 (expand-file-name
1471 vc-name-assoc-file
1472 (file-name-as-directory
1473 (expand-file-name (vc-backend-subdirectory-name file)
1474 (file-name-directory file)))))
b7011339
RS
1475 (prog1
1476 (car (vc-parse-buffer
1477 (list (list (concat name "\t:\t" file "\t\\(.+\\)") 1))))
1478 (kill-buffer "*vc-info*"))))
1479 ))
594722a8
ER
1480
1481;; Named-configuration entry points
1482
503b5c85
RS
1483(defun vc-snapshot-precondition ()
1484 ;; Scan the tree below the current directory.
1485 ;; If any files are locked, return the name of the first such file.
1486 ;; (This means, neither snapshot creation nor retrieval is allowed.)
1487 ;; If one or more of the files are currently visited, return `visited'.
1488 ;; Otherwise, return nil.
1489 (let ((status nil))
1490 (catch 'vc-locked-example
1491 (vc-file-tree-walk
2f119435 1492 default-directory
503b5c85
RS
1493 (function (lambda (f)
1494 (and (vc-registered f)
1495 (if (vc-locking-user f) (throw 'vc-locked-example f)
1496 (if (get-file-buffer f) (setq status 'visited)))))))
1497 status)))
594722a8 1498
637a8ae9 1499;;;###autoload
594722a8
ER
1500(defun vc-create-snapshot (name)
1501 "Make a snapshot called NAME.
1502The snapshot is made from all registered files at or below the current
1503directory. For each file, the version level of its latest
1504version becomes part of the named configuration."
1505 (interactive "sNew snapshot name: ")
503b5c85
RS
1506 (let ((result (vc-snapshot-precondition)))
1507 (if (stringp result)
1508 (error "File %s is locked" result)
1dabb4e6 1509 (vc-file-tree-walk
2f119435 1510 default-directory
1dabb4e6
PE
1511 (function (lambda (f) (and
1512 (vc-name f)
1513 (vc-backend-assign-name f name)))))
1514 )))
594722a8 1515
637a8ae9 1516;;;###autoload
594722a8
ER
1517(defun vc-retrieve-snapshot (name)
1518 "Retrieve the snapshot called NAME.
1519This function fails if any files are locked at or below the current directory
1520Otherwise, all registered files are checked out (unlocked) at their version
1521levels in the snapshot."
1522 (interactive "sSnapshot name to retrieve: ")
503b5c85
RS
1523 (let ((result (vc-snapshot-precondition))
1524 (update nil))
1525 (if (stringp result)
1526 (error "File %s is locked" result)
1527 (if (eq result 'visited)
1528 (setq update (yes-or-no-p "Update the affected buffers? ")))
1dabb4e6 1529 (vc-file-tree-walk
2f119435 1530 default-directory
1dabb4e6
PE
1531 (function (lambda (f) (and
1532 (vc-name f)
1533 (vc-error-occurred
503b5c85
RS
1534 (vc-backend-checkout f nil name)
1535 (if update (vc-resynch-buffer f t t)))))))
1dabb4e6 1536 )))
594722a8
ER
1537
1538;; Miscellaneous other entry points
1539
637a8ae9 1540;;;###autoload
594722a8
ER
1541(defun vc-print-log ()
1542 "List the change log of the current buffer in a window."
1543 (interactive)
e1f297e6
ER
1544 (if vc-dired-mode
1545 (set-buffer (find-file-noselect (dired-get-filename))))
8ac8c82f 1546 (while vc-parent-buffer
1a2f456b 1547 (pop-to-buffer vc-parent-buffer))
594722a8 1548 (if (and buffer-file-name (vc-name buffer-file-name))
632e9525
RS
1549 (let ((file buffer-file-name))
1550 (vc-backend-print-log file)
594722a8 1551 (pop-to-buffer (get-buffer-create "*vc*"))
632e9525 1552 (setq default-directory (file-name-directory file))
4805f679
BF
1553 (while (looking-at "=*\n")
1554 (delete-char (- (match-end 0) (match-beginning 0)))
1555 (forward-line -1))
594722a8 1556 (goto-char (point-min))
4805f679
BF
1557 (if (looking-at "[\b\t\n\v\f\r ]+")
1558 (delete-char (- (match-end 0) (match-beginning 0))))
4c2d8cf9 1559 (shrink-window-if-larger-than-buffer)
594722a8 1560 )
7ef84cf9 1561 (vc-registration-error buffer-file-name)
594722a8
ER
1562 )
1563 )
1564
637a8ae9 1565;;;###autoload
594722a8 1566(defun vc-revert-buffer ()
9c95ac44
RS
1567 "Revert the current buffer's file back to the latest checked-in version.
1568This asks for confirmation if the buffer contents are not identical
80688f5c
RS
1569to that version.
1570If the back-end is CVS, this will give you the most recent revision of
1571the file on the branch you are editing."
594722a8 1572 (interactive)
e1f297e6
ER
1573 (if vc-dired-mode
1574 (find-file-other-window (dired-get-filename)))
8ac8c82f 1575 (while vc-parent-buffer
1a2f456b 1576 (pop-to-buffer vc-parent-buffer))
594722a8 1577 (let ((file buffer-file-name)
97d3f950 1578 (obuf (current-buffer)) (changed (vc-diff nil t)))
9c95ac44
RS
1579 (if (and changed (or vc-suppress-confirm
1580 (not (yes-or-no-p "Discard changes? "))))
594722a8 1581 (progn
fab2e906
RS
1582 (if (and (window-dedicated-p (selected-window))
1583 (one-window-p t 'selected-frame))
1584 (make-frame-invisible (selected-frame))
1585 (delete-window))
590cc449 1586 (error "Revert cancelled"))
594722a8
ER
1587 (set-buffer obuf))
1588 (if changed
fab2e906
RS
1589 (if (and (window-dedicated-p (selected-window))
1590 (one-window-p t 'selected-frame))
1591 (make-frame-invisible (selected-frame))
1592 (delete-window)))
594722a8 1593 (vc-backend-revert file)
624b4662 1594 (vc-resynch-window file t t)
594722a8
ER
1595 )
1596 )
1597
637a8ae9 1598;;;###autoload
594722a8 1599(defun vc-cancel-version (norevert)
34291cd2
RS
1600 "Get rid of most recently checked in version of this file.
1601A prefix argument means do not revert the buffer afterwards."
594722a8 1602 (interactive "P")
e1f297e6
ER
1603 (if vc-dired-mode
1604 (find-file-other-window (dired-get-filename)))
8ac8c82f
ER
1605 (while vc-parent-buffer
1606 (pop-to-buffer vc-parent-buffer))
c8de1d91
AS
1607 (cond
1608 ((eq (vc-backend (buffer-file-name)) 'CVS)
1609 (error "Unchecking files under CVS is dangerous and not supported in VC"))
1610 ((vc-locking-user (buffer-file-name))
1611 (error "This version is locked. Use vc-revert-buffer to discard changes."))
1612 ((not (vc-latest-on-branch-p (buffer-file-name)))
1613 (error "This is not the latest version. VC cannot cancel it.")))
1614 (let ((target (vc-workfile-version (buffer-file-name))))
1615 (if (null (yes-or-no-p "Remove this version from master? "))
7b4f934d 1616 nil
c8de1d91
AS
1617 (setq norevert (or norevert (not
1618 (yes-or-no-p "Revert buffer to most recent remaining version? "))))
7b4f934d 1619 (vc-backend-uncheck (buffer-file-name) target)
c8de1d91
AS
1620 (if (not norevert)
1621 (vc-checkout (buffer-file-name) nil)
1622 ;; If norevert, lock the most recent remaining version,
1623 ;; and mark the buffer modified.
1624 (if (eq (vc-backend (buffer-file-name)) 'RCS)
1625 (progn (setq buffer-read-only nil)
1626 (vc-clear-headers)))
1627 (vc-backend-checkout (buffer-file-name) t (vc-branch-part target))
1628 (set-visited-file-name (buffer-file-name))
1629 (vc-mode-line (buffer-file-name)))
1630 (message "Version %s has been removed from the master." target)
1631 )))
594722a8 1632
29fc1ce9 1633;;;###autoload
594722a8 1634(defun vc-rename-file (old new)
34291cd2
RS
1635 "Rename file OLD to NEW, and rename its master file likewise."
1636 (interactive "fVC rename file: \nFRename to: ")
80688f5c
RS
1637 ;; There are several ways of renaming files under CVS 1.3, but they all
1638 ;; have serious disadvantages. See the FAQ (available from think.com in
1639 ;; pub/cvs/). I'd rather send the user an error, than do something he might
1640 ;; consider to be wrong. When the famous, long-awaited rename database is
1641 ;; implemented things might change for the better. This is unlikely to occur
1642 ;; until CVS 2.0 is released. --ceder 1994-01-23 21:27:51
f3c61d82 1643 (if (eq (vc-backend old) 'CVS)
80688f5c 1644 (error "Renaming files under CVS is dangerous and not supported in VC."))
594722a8 1645 (let ((oldbuf (get-file-buffer old)))
d52f0de9 1646 (if (and oldbuf (buffer-modified-p oldbuf))
590cc449 1647 (error "Please save files before moving them"))
594722a8 1648 (if (get-file-buffer new)
590cc449 1649 (error "Already editing new file name"))
d52f0de9
RS
1650 (if (file-exists-p new)
1651 (error "New file already exists"))
594722a8
ER
1652 (let ((oldmaster (vc-name old)))
1653 (if oldmaster
d52f0de9
RS
1654 (progn
1655 (if (vc-locking-user old)
1656 (error "Please check in files before moving them"))
1657 (if (or (file-symlink-p oldmaster)
1658 ;; This had FILE, I changed it to OLD. -- rms.
1659 (file-symlink-p (vc-backend-subdirectory-name old)))
1660 (error "This is not a safe thing to do in the presence of symbolic links"))
1661 (rename-file
1662 oldmaster
f3c61d82 1663 (let ((backend (vc-backend old))
d52f0de9
RS
1664 (newdir (or (file-name-directory new) ""))
1665 (newbase (file-name-nondirectory new)))
1666 (catch 'found
1667 (mapcar
1668 (function
1669 (lambda (s)
1670 (if (eq backend (cdr s))
1671 (let* ((newmaster (format (car s) newdir newbase))
1672 (newmasterdir (file-name-directory newmaster)))
1673 (if (or (not newmasterdir)
1674 (file-directory-p newmasterdir))
1675 (throw 'found newmaster))))))
1676 vc-master-templates)
1677 (error "New file lacks a version control directory"))))))
594722a8
ER
1678 (if (or (not oldmaster) (file-exists-p old))
1679 (rename-file old new)))
1680; ?? Renaming a file might change its contents due to keyword expansion.
1681; We should really check out a new copy if the old copy was precisely equal
1682; to some checked in version. However, testing for this is tricky....
1683 (if oldbuf
1684 (save-excursion
1685 (set-buffer oldbuf)
1686 (set-visited-file-name new)
1687 (set-buffer-modified-p nil))))
60213ed0
RS
1688 ;; This had FILE, I changed it to OLD. -- rms.
1689 (vc-backend-dispatch old
80688f5c
RS
1690 (vc-record-rename old new) ;SCCS
1691 nil ;RCS
1692 nil ;CVS
1693 )
594722a8
ER
1694 )
1695
637a8ae9 1696;;;###autoload
f35ecf88
RM
1697(defun vc-update-change-log (&rest args)
1698 "Find change log file and add entries from recent RCS logs.
1699The mark is left at the end of the text prepended to the change log.
1700With prefix arg of C-u, only find log entries for the current buffer's file.
1701With any numeric prefix arg, find log entries for all files currently visited.
4b40fdea 1702Otherwise, find log entries for all registered files in the default directory.
f35ecf88 1703From a program, any arguments are passed to the `rcs2log' script."
67242a23
RM
1704 (interactive
1705 (cond ((consp current-prefix-arg) ;C-u
1706 (list buffer-file-name))
1707 (current-prefix-arg ;Numeric argument.
1708 (let ((files nil)
1709 (buffers (buffer-list))
1710 file)
1711 (while buffers
1712 (setq file (buffer-file-name (car buffers)))
f3c61d82 1713 (and file (vc-backend file)
4b40fdea 1714 (setq files (cons file files)))
67242a23 1715 (setq buffers (cdr buffers)))
4b40fdea
PE
1716 files))
1717 (t
1718 (let ((RCS (concat default-directory "RCS")))
1719 (and (file-directory-p RCS)
1720 (mapcar (function
1721 (lambda (f)
1722 (if (string-match "\\(.*\\),v$" f)
1723 (substring f 0 (match-end 1))
1724 f)))
1725 (directory-files RCS nil "...\\|^[^.]\\|^.[^.]")))))))
41dfb835
RS
1726 (let ((odefault default-directory))
1727 (find-file-other-window (find-change-log))
1728 (barf-if-buffer-read-only)
1729 (vc-buffer-sync)
1730 (undo-boundary)
1731 (goto-char (point-min))
1732 (push-mark)
1733 (message "Computing change log entries...")
4b40fdea
PE
1734 (message "Computing change log entries... %s"
1735 (if (or (null args)
1736 (eq 0 (apply 'call-process "rcs2log" nil t nil
243a81f5
RS
1737 "-u"
1738 (concat (user-login-name)
1739 "\t"
1740 (user-full-name)
1741 "\t"
1742 user-mail-address)
4b40fdea
PE
1743 (mapcar (function
1744 (lambda (f)
1745 (file-relative-name
1746 (if (file-name-absolute-p f)
1747 f
1748 (concat odefault f)))))
1749 args))))
1750 "done" "failed"))))
594722a8 1751
c6d4f628 1752;; Collect back-end-dependent stuff here
594722a8 1753
594722a8
ER
1754(defun vc-backend-admin (file &optional rev comment)
1755 ;; Register a file into the version-control system
1756 ;; Automatically retrieves a read-only version of the file with
1757 ;; keywords expanded if vc-keep-workfiles is non-nil, otherwise
1758 ;; it deletes the workfile.
1759 (vc-file-clearprops file)
1760 (or vc-default-back-end
1761 (setq vc-default-back-end (if (vc-find-binary "rcs") 'RCS 'SCCS)))
1762 (message "Registering %s..." file)
1763 (let ((backend
1764 (cond
1765 ((file-exists-p (vc-backend-subdirectory-name)) vc-default-back-end)
1766 ((file-exists-p "RCS") 'RCS)
1767 ((file-exists-p "SCCS") 'SCCS)
80688f5c 1768 ((file-exists-p "CVS") 'CVS)
594722a8
ER
1769 (t vc-default-back-end))))
1770 (cond ((eq backend 'SCCS)
6aa13729 1771 (vc-do-command nil 0 "admin" file 'MASTER ;; SCCS
594722a8
ER
1772 (and rev (concat "-r" rev))
1773 "-fb"
1774 (concat "-i" file)
1775 (and comment (concat "-y" comment))
1776 (format
1777 (car (rassq 'SCCS vc-master-templates))
1778 (or (file-name-directory file) "")
1779 (file-name-nondirectory file)))
1780 (delete-file file)
1781 (if vc-keep-workfiles
6aa13729 1782 (vc-do-command nil 0 "get" file 'MASTER)))
594722a8 1783 ((eq backend 'RCS)
6aa13729 1784 (vc-do-command nil 0 "ci" file 'MASTER ;; RCS
b0c9bc8c
AS
1785 ;; if available, use the secure registering option
1786 (and (vc-backend-release-p 'RCS "5.6.4") "-i")
594722a8
ER
1787 (concat (if vc-keep-workfiles "-u" "-r") rev)
1788 (and comment (concat "-t-" comment))
80688f5c
RS
1789 file))
1790 ((eq backend 'CVS)
6aa13729 1791 (vc-do-command nil 0 "cvs" file 'WORKFILE ;; CVS
80688f5c 1792 "add"
9e0cc6e6 1793 (and comment (string-match "[^\t\n ]" comment)
80688f5c 1794 (concat "-m" comment)))
594722a8
ER
1795 )))
1796 (message "Registering %s...done" file)
1797 )
1798
f1818994 1799(defun vc-backend-checkout (file &optional writable rev workfile)
594722a8 1800 ;; Retrieve a copy of a saved version into a workfile
503b5c85
RS
1801 (let ((filename (or workfile file))
1802 (file-buffer (get-file-buffer file))
1803 (old-default-dir default-directory))
f1818994 1804 (message "Checking out %s..." filename)
f797cb30
RM
1805 (save-excursion
1806 ;; Change buffers to get local value of vc-checkin-switches.
503b5c85
RS
1807 (if file-buffer (set-buffer file-buffer))
1808 ;; Adjust the default-directory so that the check-out creates
1809 ;; the file in the right place. The old value is restored below.
1810 (setq default-directory (file-name-directory filename))
f797cb30
RM
1811 (vc-backend-dispatch file
1812 (if workfile;; SCCS
1813 ;; Some SCCS implementations allow checking out directly to a
1814 ;; file using the -G option, but then some don't so use the
1815 ;; least common denominator approach and use the -p option
1816 ;; ala RCS.
1817 (let ((vc-modes (logior (file-modes (vc-name file))
1818 (if writable 128 0)))
1819 (failed t))
1820 (unwind-protect
1821 (progn
1822 (apply 'vc-do-command
6aa13729 1823 nil 0 "/bin/sh" file 'MASTER "-c"
f797cb30
RM
1824 ;; Some shells make the "" dummy argument into $0
1825 ;; while others use the shell's name as $0 and
1826 ;; use the "" as $1. The if-statement
1827 ;; converts the latter case to the former.
1828 (format "if [ x\"$1\" = x ]; then shift; fi; \
29fc1ce9
RS
1829 umask %o; exec >\"$1\" || exit; \
1830 shift; umask %o; exec get \"$@\""
f797cb30
RM
1831 (logand 511 (lognot vc-modes))
1832 (logand 511 (lognot (default-file-modes))))
1833 "" ; dummy argument for shell's $0
1834 filename
1835 (if writable "-e")
1836 "-p" (and rev
1837 (concat "-r" (vc-lookup-triple file rev)))
1838 vc-checkout-switches)
1839 (setq failed nil))
1840 (and failed (file-exists-p filename) (delete-file filename))))
6aa13729 1841 (apply 'vc-do-command nil 0 "get" file 'MASTER ;; SCCS
f797cb30 1842 (if writable "-e")
c6d4f628 1843 (and rev (concat "-r" (vc-lookup-triple file rev)))
88a2ffaf
RS
1844 vc-checkout-switches)
1845 (vc-file-setprop file 'vc-workfile-version nil))
6aa13729 1846 (if workfile ;; RCS
f797cb30
RM
1847 ;; RCS doesn't let us check out into arbitrary file names directly.
1848 ;; Use `co -p' and make stdout point to the correct file.
1849 (let ((vc-modes (logior (file-modes (vc-name file))
1850 (if writable 128 0)))
1851 (failed t))
1852 (unwind-protect
1853 (progn
1854 (apply 'vc-do-command
6aa13729 1855 nil 0 "/bin/sh" file 'MASTER "-c"
f797cb30
RM
1856 ;; See the SCCS case, above, regarding the
1857 ;; if-statement.
1858 (format "if [ x\"$1\" = x ]; then shift; fi; \
29fc1ce9
RS
1859 umask %o; exec >\"$1\" || exit; \
1860 shift; umask %o; exec co \"$@\""
f797cb30
RM
1861 (logand 511 (lognot vc-modes))
1862 (logand 511 (lognot (default-file-modes))))
1863 "" ; dummy argument for shell's $0
1864 filename
1865 (if writable "-l")
1866 (concat "-p" rev)
1867 vc-checkout-switches)
1868 (setq failed nil))
1869 (and failed (file-exists-p filename) (delete-file filename))))
e163b283
AS
1870 (let (new-version)
1871 ;; if we should go to the head of the trunk,
1872 ;; clear the default branch first
1873 (and rev (string= rev "")
1874 (vc-do-command nil 0 "rcs" file 'MASTER "-b"))
1875 ;; now do the checkout
c6d4f628 1876 (apply 'vc-do-command
6aa13729 1877 nil 0 "co" file 'MASTER
8e7eda1a
AS
1878 ;; If locking is not strict, force to overwrite
1879 ;; the writable workfile.
1880 (if (eq (vc-checkout-model file) 'implicit) "-f")
c6d4f628
RS
1881 (if writable "-l")
1882 (if rev (concat "-r" rev)
1883 ;; if no explicit revision was specified,
1884 ;; check out that of the working file
1885 (let ((workrev (vc-workfile-version file)))
1886 (if workrev (concat "-r" workrev)
1887 nil)))
1888 vc-checkout-switches)
e163b283 1889 ;; determine the new workfile version
c6d4f628
RS
1890 (save-excursion
1891 (set-buffer "*vc*")
1892 (goto-char (point-min))
e163b283
AS
1893 (setq new-version
1894 (if (re-search-forward "^revision \\([0-9.]+\\).*\n" nil t)
1895 (buffer-substring (match-beginning 1) (match-end 1)))))
1896 (vc-file-setprop file 'vc-workfile-version new-version)
1897 ;; if necessary, adjust the default branch
1898 (and rev (not (string= rev ""))
1899 (vc-do-command nil 0 "rcs" file 'MASTER
1900 (concat "-b" (if (vc-latest-on-branch-p file)
1901 (if (vc-trunk-p new-version) nil
1902 (vc-branch-part new-version))
1903 new-version))))))
1904 (if workfile ;; CVS
f797cb30
RM
1905 ;; CVS is much like RCS
1906 (let ((failed t))
1907 (unwind-protect
1908 (progn
1909 (apply 'vc-do-command
6aa13729 1910 nil 0 "/bin/sh" file 'WORKFILE "-c"
f797cb30
RM
1911 "exec >\"$1\" || exit; shift; exec cvs update \"$@\""
1912 "" ; dummy argument for shell's $0
1913 workfile
1914 (concat "-r" rev)
1915 "-p"
1916 vc-checkout-switches)
1917 (setq failed nil))
1918 (and failed (file-exists-p filename) (delete-file filename))))
61dee1e7 1919 ;; default for verbose checkout: clear the sticky tag
8dd71345 1920 ;; so that the actual update will get the head of the trunk
61dee1e7 1921 (and rev (string= rev "")
8e7eda1a
AS
1922 (vc-do-command nil 0 "cvs" file 'WORKFILE "update" "-A"))
1923 ;; If a revision was specified, check that out.
1924 (if rev
1925 (apply 'vc-do-command nil 0 "cvs" file 'WORKFILE
1926 (and writable (eq (vc-checkout-model file) 'manual) "-w")
1927 "update"
1928 (and rev (not (string= rev ""))
1929 (concat "-r" rev))
1930 vc-checkout-switches)
1931 ;; If no revision was specified, simply make the file writable.
1932 (and writable
1933 (or (eq (vc-checkout-model file) 'manual)
1934 (zerop (logand 128 (file-modes file))))
1935 (set-file-modes file (logior 128 (file-modes file)))))
1936 (if rev (vc-file-setprop file 'vc-workfile-version nil))))
503b5c85 1937 (setq default-directory old-default-dir)
88a2ffaf
RS
1938 (cond
1939 ((not workfile)
1940 (vc-file-clear-masterprops file)
1941 (if writable
1942 (vc-file-setprop file 'vc-locking-user (user-login-name)))
1943 (vc-file-setprop file
1944 'vc-checkout-time (nth 5 (file-attributes file)))))
8e7eda1a 1945 (message "Checking out %s...done" filename))))
594722a8
ER
1946
1947(defun vc-backend-logentry-check (file)
1948 (vc-backend-dispatch file
8c0aaf40 1949 (if (>= (buffer-size) 512) ;; SCCS
594722a8
ER
1950 (progn
1951 (goto-char 512)
1952 (error
590cc449 1953 "Log must be less than 512 characters; point is now at pos 512")))
80688f5c
RS
1954 nil ;; RCS
1955 nil) ;; CVS
594722a8
ER
1956 )
1957
80688f5c 1958(defun vc-backend-checkin (file rev comment)
594722a8
ER
1959 ;; Register changes to FILE as level REV with explanatory COMMENT.
1960 ;; Automatically retrieves a read-only version of the file with
1961 ;; keywords expanded if vc-keep-workfiles is non-nil, otherwise
1962 ;; it deletes the workfile.
c6d4f628
RS
1963 ;; Adaption for RCS branch support: if this is an explicit checkin,
1964 ;; or if the checkin creates a new branch, set the master file branch
1965 ;; accordingly.
594722a8 1966 (message "Checking in %s..." file)
7d665008 1967 ;; "This log message intentionally left almost blank".
9e0cc6e6
RS
1968 ;; RCS 5.7 gripes about white-space-only comments too.
1969 (or (and comment (string-match "[^\t\n ]" comment))
1970 (setq comment "*** empty log message ***"))
2ea8ce47
RM
1971 (save-excursion
1972 ;; Change buffers to get local value of vc-checkin-switches.
1973 (set-buffer (or (get-file-buffer file) (current-buffer)))
61dee1e7
AS
1974 ;; Clear the master-properties. Do that here, not at the
1975 ;; end, because if the check-in fails we want them to get
1976 ;; re-computed before the next try.
1977 (vc-file-clear-masterprops file)
2ea8ce47 1978 (vc-backend-dispatch file
c6d4f628 1979 ;; SCCS
2ea8ce47 1980 (progn
6aa13729 1981 (apply 'vc-do-command nil 0 "delta" file 'MASTER
2ea8ce47
RM
1982 (if rev (concat "-r" rev))
1983 (concat "-y" comment)
1984 vc-checkin-switches)
88a2ffaf 1985 (vc-file-setprop file 'vc-locking-user 'none)
c6d4f628 1986 (vc-file-setprop file 'vc-workfile-version nil)
2ea8ce47 1987 (if vc-keep-workfiles
6aa13729 1988 (vc-do-command nil 0 "get" file 'MASTER))
2ea8ce47 1989 )
c6d4f628 1990 ;; RCS
88a2ffaf 1991 (let ((old-version (vc-workfile-version file)) new-version)
6aa13729 1992 (apply 'vc-do-command nil 0 "ci" file 'MASTER
b0c9bc8c
AS
1993 ;; if available, use the secure check-in option
1994 (and (vc-backend-release-p 'RCS "5.6.4") "-j")
c6d4f628
RS
1995 (concat (if vc-keep-workfiles "-u" "-r") rev)
1996 (concat "-m" comment)
1997 vc-checkin-switches)
88a2ffaf 1998 (vc-file-setprop file 'vc-locking-user 'none)
c6d4f628
RS
1999 (vc-file-setprop file 'vc-workfile-version nil)
2000
88a2ffaf
RS
2001 ;; determine the new workfile version
2002 (set-buffer "*vc*")
2003 (goto-char (point-min))
2004 (if (or (re-search-forward
2005 "new revision: \\([0-9.]+\\);" nil t)
2006 (re-search-forward
2007 "reverting to previous revision \\([0-9.]+\\)" nil t))
2008 (progn (setq new-version (buffer-substring (match-beginning 1)
2009 (match-end 1)))
2010 (vc-file-setprop file 'vc-workfile-version new-version)))
2011
2012 ;; if we got to a different branch, adjust the default
b0c9bc8c 2013 ;; branch accordingly
88a2ffaf
RS
2014 (cond
2015 ((and old-version new-version
2016 (not (string= (vc-branch-part old-version)
2017 (vc-branch-part new-version))))
6aa13729 2018 (vc-do-command nil 0 "rcs" file 'MASTER
88a2ffaf
RS
2019 (if (vc-trunk-p new-version) "-b"
2020 (concat "-b" (vc-branch-part new-version))))
b0c9bc8c
AS
2021 ;; If this is an old RCS release, we might have
2022 ;; to remove a remaining lock.
2023 (if (not (vc-backend-release-p 'RCS "5.6.2"))
2024 ;; exit status of 1 is also accepted.
2025 ;; It means that the lock was removed before.
2026 (vc-do-command nil 1 "rcs" file 'MASTER
2027 (concat "-u" old-version))))))
c6d4f628 2028 ;; CVS
80688f5c 2029 (progn
c6d4f628
RS
2030 ;; explicit check-in to the trunk requires a
2031 ;; double check-in (first unexplicit) (CVS-1.3)
61dee1e7
AS
2032 (condition-case nil
2033 (progn
2034 (if (and rev (vc-trunk-p rev))
2035 (apply 'vc-do-command nil 0 "cvs" file 'WORKFILE
2036 "ci" "-m" "intermediate"
2037 vc-checkin-switches))
2038 (apply 'vc-do-command nil 0 "cvs" file 'WORKFILE
2039 "ci" (if rev (concat "-r" rev))
2040 (concat "-m" comment)
2041 vc-checkin-switches))
2042 (error (if (eq (vc-cvs-status file) 'needs-merge)
2043 ;; The CVS output will be on top of this message.
2044 (error "Type C-x 0 C-x C-q to merge in changes.")
2045 (error "Check in FAILED."))))
c6d4f628
RS
2046 ;; determine and store the new workfile version
2047 (set-buffer "*vc*")
2048 (goto-char (point-min))
2049 (if (re-search-forward
2050 "^\\(new\\|initial\\) revision: \\([0-9.]+\\)" nil t)
2051 (vc-file-setprop file 'vc-workfile-version
2052 (buffer-substring (match-beginning 2)
2053 (match-end 2)))
2054 (vc-file-setprop file 'vc-workfile-version nil))
2055 ;; if this was an explicit check-in, remove the sticky tag
2056 (if rev
6aa13729 2057 (vc-do-command nil 0 "cvs" file 'WORKFILE "update" "-A"))
88a2ffaf 2058 (vc-file-setprop file 'vc-locking-user 'none)
80688f5c 2059 (vc-file-setprop file 'vc-checkout-time
c6d4f628 2060 (nth 5 (file-attributes file))))))
88a2ffaf 2061 (message "Checking in %s...done" file))
594722a8
ER
2062
2063(defun vc-backend-revert (file)
2064 ;; Revert file to latest checked-in version.
c6d4f628 2065 ;; (for RCS, to workfile version)
594722a8 2066 (message "Reverting %s..." file)
61dee1e7 2067 (vc-file-clear-masterprops file)
594722a8
ER
2068 (vc-backend-dispatch
2069 file
c6d4f628
RS
2070 ;; SCCS
2071 (progn
6aa13729
RS
2072 (vc-do-command nil 0 "unget" file 'MASTER nil)
2073 (vc-do-command nil 0 "get" file 'MASTER nil))
c6d4f628 2074 ;; RCS
6aa13729 2075 (vc-do-command nil 0 "co" file 'MASTER
c6d4f628
RS
2076 "-f" (concat "-u" (vc-workfile-version file)))
2077 ;; CVS
2078 (progn
80688f5c 2079 (delete-file file)
6aa13729 2080 (vc-do-command nil 0 "cvs" file 'WORKFILE "update")))
88a2ffaf 2081 (vc-file-setprop file 'vc-locking-user 'none)
c6d4f628 2082 (vc-file-setprop file 'vc-checkout-time (nth 5 (file-attributes file)))
594722a8
ER
2083 (message "Reverting %s...done" file)
2084 )
2085
2086(defun vc-backend-steal (file &optional rev)
2087 ;; Steal the lock on the current workfile. Needs RCS 5.6.2 or later for -M.
2088 (message "Stealing lock on %s..." file)
af1b8606 2089 (vc-backend-dispatch file
80688f5c 2090 (progn ;SCCS
6aa13729
RS
2091 (vc-do-command nil 0 "unget" file 'MASTER "-n" (if rev (concat "-r" rev)))
2092 (vc-do-command nil 0 "get" file 'MASTER "-g" (if rev (concat "-r" rev)))
d76b8d38 2093 )
6aa13729 2094 (vc-do-command nil 0 "rcs" file 'MASTER ;RCS
80688f5c
RS
2095 "-M" (concat "-u" rev) (concat "-l" rev))
2096 (error "You cannot steal a CVS lock; there are no CVS locks to steal.") ;CVS
2097 )
594722a8
ER
2098 (vc-file-setprop file 'vc-locking-user (user-login-name))
2099 (message "Stealing lock on %s...done" file)
2100 )
2101
2102(defun vc-backend-uncheck (file target)
c8de1d91 2103 ;; Undo the latest checkin.
594722a8
ER
2104 (message "Removing last change from %s..." file)
2105 (vc-backend-dispatch file
6aa13729
RS
2106 (vc-do-command nil 0 "rmdel" file 'MASTER (concat "-r" target))
2107 (vc-do-command nil 0 "rcs" file 'MASTER (concat "-o" target))
88a2ffaf 2108 nil ;; this is never reached under CVS
594722a8
ER
2109 )
2110 (message "Removing last change from %s...done" file)
2111 )
2112
2113(defun vc-backend-print-log (file)
6aa13729 2114 ;; Get change log associated with FILE.
80688f5c
RS
2115 (vc-backend-dispatch
2116 file
6aa13729
RS
2117 (vc-do-command nil 0 "prs" file 'MASTER)
2118 (vc-do-command nil 0 "rlog" file 'MASTER)
2119 (vc-do-command nil 0 "cvs" file 'WORKFILE "rlog")))
594722a8
ER
2120
2121(defun vc-backend-assign-name (file name)
2122 ;; Assign to a FILE's latest version a given NAME.
2123 (vc-backend-dispatch file
6aa13729
RS
2124 (vc-add-triple name file (vc-latest-version file)) ;; SCCS
2125 (vc-do-command nil 0 "rcs" file 'MASTER (concat "-n" name ":")) ;; RCS
2126 (vc-do-command nil 0 "cvs" file 'WORKFILE "tag" name) ;; CVS
3234e2a3 2127 )
3234e2a3 2128 )
594722a8 2129
9a51ed3a
PE
2130(defun vc-backend-diff (file &optional oldvers newvers cmp)
2131 ;; Get a difference report between two versions of FILE.
2132 ;; Get only a brief comparison report if CMP, a difference report otherwise.
f3c61d82 2133 (let ((backend (vc-backend file)))
80688f5c
RS
2134 (cond
2135 ((eq backend 'SCCS)
7b4f934d 2136 (setq oldvers (vc-lookup-triple file oldvers))
c6d4f628
RS
2137 (setq newvers (vc-lookup-triple file newvers)))
2138 ((eq backend 'RCS)
2139 (if (not oldvers) (setq oldvers (vc-workfile-version file)))))
80688f5c 2140 ;; SCCS and RCS shares a lot of code.
c6d4f628 2141 (cond
80688f5c
RS
2142 ((or (eq backend 'SCCS) (eq backend 'RCS))
2143 (let* ((command (if (eq backend 'SCCS)
2144 "vcdiff"
2145 "rcsdiff"))
632e9525 2146 (mode (if (eq backend 'RCS) 'WORKFILE 'MASTER))
80688f5c
RS
2147 (options (append (list (and cmp "--brief")
2148 "-q"
2149 (and oldvers (concat "-r" oldvers))
2150 (and newvers (concat "-r" newvers)))
2151 (and (not cmp)
2152 (if (listp diff-switches)
2153 diff-switches
2154 (list diff-switches)))))
6aa13729
RS
2155 (status (apply 'vc-do-command "*vc-diff*" 2
2156 command file mode options)))
80688f5c
RS
2157 ;; Some RCS versions don't understand "--brief"; work around this.
2158 (if (eq status 2)
6aa13729 2159 (apply 'vc-do-command "*vc-diff*" 1 command file 'WORKFILE
80688f5c
RS
2160 (if cmp (cdr options) options))
2161 status)))
2162 ;; CVS is different.
80688f5c 2163 ((eq backend 'CVS)
c6d4f628 2164 (if (string= (vc-workfile-version file) "0") ;CVS
80688f5c 2165 ;; This file is added but not yet committed; there is no master file.
80688f5c 2166 (if (or oldvers newvers)
b0c9bc8c
AS
2167 (error "No revisions of %s exist" file)
2168 (if cmp 1 ;; file is added but not committed,
2169 ;; we regard this as "changed".
2170 ;; diff it against /dev/null.
2171 (apply 'vc-do-command
2172 "*vc-diff*" 1 "diff" file 'WORKFILE
2173 (append (if (listp diff-switches)
2174 diff-switches
2175 (list diff-switches)) '("/dev/null")))))
2176 ;; cmp is not yet implemented -- we always do a full diff.
80688f5c 2177 (apply 'vc-do-command
6aa13729 2178 "*vc-diff*" 1 "cvs" file 'WORKFILE "diff"
80688f5c
RS
2179 (and oldvers (concat "-r" oldvers))
2180 (and newvers (concat "-r" newvers))
2181 (if (listp diff-switches)
2182 diff-switches
2183 (list diff-switches)))))
2184 (t
2185 (vc-registration-error file)))))
2186
2187(defun vc-backend-merge-news (file)
2188 ;; Merge in any new changes made to FILE.
61dee1e7
AS
2189 (message "Merging changes into %s..." file)
2190 (prog1
2191 (vc-backend-dispatch
2192 file
2193 (error "vc-backend-merge-news not meaningful for SCCS files") ;SCCS
2194 (error "vc-backend-merge-news not meaningful for RCS files") ;RCS
2195 (save-excursion ; CVS
2196 (vc-file-clear-masterprops file)
2197 (vc-file-setprop file 'vc-workfile-version nil)
2198 (vc-file-setprop file 'vc-locking-user nil)
2199 (vc-do-command nil 0 "cvs" file 'WORKFILE "update")
2200 ;; CVS doesn't return an error code if conflicts are detected.
2201 ;; Since we want to warn the user about it (and possibly start
2202 ;; emerge later), scan the output and see if this occurred.
2203 (set-buffer (get-buffer "*vc*"))
2204 (goto-char (point-min))
2205 (if (re-search-forward "^cvs update: conflicts found in .*" nil t)
2206 1 ;; error code for caller
2207 0 ;; no conflict detected
2208 )))
2209 (message "Merging changes into %s...done" file)))
594722a8
ER
2210
2211(defun vc-check-headers ()
2212 "Check if the current file has any headers in it."
2213 (interactive)
2214 (save-excursion
2215 (goto-char (point-min))
2216 (vc-backend-dispatch buffer-file-name
2217 (re-search-forward "%[MIRLBSDHTEGUYFPQCZWA]%" nil t) ;; SCCS
2218 (re-search-forward "\\$[A-Za-z\300-\326\330-\366\370-\377]+\\(: [\t -#%-\176\240-\377]*\\)?\\$" nil t) ;; RCS
80688f5c 2219 'RCS ;; CVS works like RCS in this regard.
594722a8
ER
2220 )
2221 ))
2222
2223;; Back-end-dependent stuff ends here.
2224
2225;; Set up key bindings for use while editing log messages
2226
2227(defun vc-log-mode ()
2228 "Minor mode for driving version-control tools.
2229These bindings are added to the global keymap when you enter this mode:
2230\\[vc-next-action] perform next logical version-control operation on current file
2231\\[vc-register] register current file
2232\\[vc-toggle-read-only] like next-action, but won't register files
2233\\[vc-insert-headers] insert version-control headers in current file
2234\\[vc-print-log] display change history of current file
2235\\[vc-revert-buffer] revert buffer to latest version
2236\\[vc-cancel-version] undo latest checkin
2237\\[vc-diff] show diffs between file versions
f1818994 2238\\[vc-version-other-window] visit old version in another window
594722a8
ER
2239\\[vc-directory] show all files locked by any user in or below .
2240\\[vc-update-change-log] add change log entry from recent checkins
2241
2242While you are entering a change log message for a version, the following
2243additional bindings will be in effect.
2244
2245\\[vc-finish-logentry] proceed with check in, ending log message entry
2246
2247Whenever you do a checkin, your log comment is added to a ring of
2248saved comments. These can be recalled as follows:
2249
2250\\[vc-next-comment] replace region with next message in comment ring
2251\\[vc-previous-comment] replace region with previous message in comment ring
8c0aaf40
ER
2252\\[vc-comment-search-reverse] search backward for regexp in the comment ring
2253\\[vc-comment-search-forward] search backward for regexp in the comment ring
594722a8
ER
2254
2255Entry to the change-log submode calls the value of text-mode-hook, then
2256the value of vc-log-mode-hook.
2257
2258Global user options:
2259 vc-initial-comment If non-nil, require user to enter a change
2260 comment upon first checkin of the file.
2261
2262 vc-keep-workfiles Non-nil value prevents workfiles from being
2263 deleted when changes are checked in
2264
2265 vc-suppress-confirm Suppresses some confirmation prompts,
2266 notably for reversions.
2267
7b4f934d 2268 vc-header-alist Which keywords to insert when adding headers
594722a8 2269 with \\[vc-insert-headers]. Defaults to
80688f5c
RS
2270 '(\"\%\W\%\") under SCCS, '(\"\$Id\$\") under
2271 RCS and CVS.
594722a8
ER
2272
2273 vc-static-header-alist By default, version headers inserted in C files
2274 get stuffed in a static string area so that
80688f5c
RS
2275 ident(RCS/CVS) or what(SCCS) can see them in
2276 the compiled object code. You can override
2277 this by setting this variable to nil, or change
594722a8
ER
2278 the header template by changing it.
2279
2280 vc-command-messages if non-nil, display run messages from the
2281 actual version-control utilities (this is
2282 intended primarily for people hacking vc
2283 itself).
2284"
2285 (interactive)
2286 (set-syntax-table text-mode-syntax-table)
2287 (use-local-map vc-log-entry-mode)
2288 (setq local-abbrev-table text-mode-abbrev-table)
2289 (setq major-mode 'vc-log-mode)
2290 (setq mode-name "VC-Log")
2291 (make-local-variable 'vc-log-file)
2292 (make-local-variable 'vc-log-version)
8c0aaf40 2293 (make-local-variable 'vc-comment-ring-index)
594722a8
ER
2294 (set-buffer-modified-p nil)
2295 (setq buffer-file-name nil)
2296 (run-hooks 'text-mode-hook 'vc-log-mode-hook)
2297)
2298
2299;; Initialization code, to be done just once at load-time
2300(if vc-log-entry-mode
2301 nil
2302 (setq vc-log-entry-mode (make-sparse-keymap))
2303 (define-key vc-log-entry-mode "\M-n" 'vc-next-comment)
2304 (define-key vc-log-entry-mode "\M-p" 'vc-previous-comment)
8c0aaf40 2305 (define-key vc-log-entry-mode "\M-r" 'vc-comment-search-reverse)
594722a8
ER
2306 (define-key vc-log-entry-mode "\M-s" 'vc-comment-search-forward)
2307 (define-key vc-log-entry-mode "\C-c\C-c" 'vc-finish-logentry)
2308 )
2309
2310;;; These things should probably be generally available
2311
2f119435
AS
2312(defun vc-file-tree-walk (dirname func &rest args)
2313 "Walk recursively through DIRNAME.
34291cd2 2314Invoke FUNC f ARGS on each non-directory file f underneath it."
2f119435
AS
2315 (vc-file-tree-walk-internal (expand-file-name dirname) func args)
2316 (message "Traversing directory %s...done" dirname))
02da6253
PE
2317
2318(defun vc-file-tree-walk-internal (file func args)
2319 (if (not (file-directory-p file))
2320 (apply func file args)
993a1a44 2321 (message "Traversing directory %s..." (abbreviate-file-name file))
02da6253
PE
2322 (let ((dir (file-name-as-directory file)))
2323 (mapcar
2324 (function
2325 (lambda (f) (or
2326 (string-equal f ".")
2327 (string-equal f "..")
632e9525 2328 (member f vc-directory-exclusion-list)
02da6253
PE
2329 (let ((dirf (concat dir f)))
2330 (or
2331 (file-symlink-p dirf) ;; Avoid possible loops
2332 (vc-file-tree-walk-internal dirf func args))))))
2333 (directory-files dir)))))
594722a8
ER
2334
2335(provide 'vc)
2336
2337;;; DEVELOPER'S NOTES ON CONCURRENCY PROBLEMS IN THIS CODE
2338;;;
2339;;; These may be useful to anyone who has to debug or extend the package.
c6d4f628
RS
2340;;; (Note that this information corresponds to versions 5.x. Some of it
2341;;; might have been invalidated by the additions to support branching
2342;;; and RCS keyword lookup. AS, 1995/03/24)
594722a8
ER
2343;;;
2344;;; A fundamental problem in VC is that there are time windows between
2345;;; vc-next-action's computations of the file's version-control state and
2346;;; the actions that change it. This is a window open to lossage in a
2347;;; multi-user environment; someone else could nip in and change the state
2348;;; of the master during it.
2349;;;
2350;;; The performance problem is that rlog/prs calls are very expensive; we want
2351;;; to avoid them as much as possible.
2352;;;
2353;;; ANALYSIS:
2354;;;
2355;;; The performance problem, it turns out, simplifies in practice to the
2356;;; problem of making vc-locking-user fast. The two other functions that call
2357;;; prs/rlog will not be so commonly used that the slowdown is a problem; one
2358;;; makes snapshots, the other deletes the calling user's last change in the
2359;;; master.
2360;;;
2361;;; The race condition implies that we have to either (a) lock the master
2362;;; during the entire execution of vc-next-action, or (b) detect and
2363;;; recover from errors resulting from dispatch on an out-of-date state.
2364;;;
2365;;; Alternative (a) appears to be unfeasible. The problem is that we can't
2366;;; guarantee that the lock will ever be removed. Suppose a user starts a
2367;;; checkin, the change message buffer pops up, and the user, having wandered
2368;;; off to do something else, simply forgets about it?
2369;;;
2370;;; Alternative (b), on the other hand, works well with a cheap way to speed up
2371;;; vc-locking-user. Usually, if a file is registered, we can read its locked/
2372;;; unlocked state and its current owner from its permissions.
2373;;;
2374;;; This shortcut will fail if someone has manually changed the workfile's
2375;;; permissions; also if developers are munging the workfile in several
2376;;; directories, with symlinks to a master (in this latter case, the
2377;;; permissions shortcut will fail to detect a lock asserted from another
2378;;; directory).
2379;;;
2380;;; Note that these cases correspond exactly to the errors which could happen
2381;;; because of a competing checkin/checkout race in between two instances of
2382;;; vc-next-action.
2383;;;
2384;;; For VC's purposes, a workfile/master pair may have the following states:
2385;;;
2386;;; A. Unregistered. There is a workfile, there is no master.
2387;;;
2388;;; B. Registered and not locked by anyone.
2389;;;
2390;;; C. Locked by calling user and unchanged.
2391;;;
2392;;; D. Locked by the calling user and changed.
2393;;;
2394;;; E. Locked by someone other than the calling user.
2395;;;
2396;;; This makes for 25 states and 20 error conditions. Here's the matrix:
2397;;;
2398;;; VC's idea of state
2399;;; |
2400;;; V Actual state RCS action SCCS action Effect
2401;;; A B C D E
2402;;; A . 1 2 3 4 ci -u -t- admin -fb -i<file> initial admin
2403;;; B 5 . 6 7 8 co -l get -e checkout
2404;;; C 9 10 . 11 12 co -u unget; get revert
2405;;; D 13 14 15 . 16 ci -u -m<comment> delta -y<comment>; get checkin
b0c9bc8c 2406;;; E 17 18 19 20 . rcs -u -M -l unget -n ; get -g steal lock
594722a8
ER
2407;;;
2408;;; All commands take the master file name as a last argument (not shown).
2409;;;
2410;;; In the discussion below, a "self-race" is a pathological situation in
2411;;; which VC operations are being attempted simultaneously by two or more
2412;;; Emacsen running under the same username.
2413;;;
2414;;; The vc-next-action code has the following windows:
2415;;;
2416;;; Window P:
2417;;; Between the check for existence of a master file and the call to
2418;;; admin/checkin in vc-buffer-admin (apparent state A). This window may
2419;;; never close if the initial-comment feature is on.
2420;;;
2421;;; Window Q:
2422;;; Between the call to vc-workfile-unchanged-p in and the immediately
2423;;; following revert (apparent state C).
2424;;;
2425;;; Window R:
2426;;; Between the call to vc-workfile-unchanged-p in and the following
2427;;; checkin (apparent state D). This window may never close.
2428;;;
2429;;; Window S:
2430;;; Between the unlock and the immediately following checkout during a
2431;;; revert operation (apparent state C). Included in window Q.
2432;;;
2433;;; Window T:
2434;;; Between vc-locking-user and the following checkout (apparent state B).
2435;;;
2436;;; Window U:
2437;;; Between vc-locking-user and the following revert (apparent state C).
2438;;; Includes windows Q and S.
2439;;;
2440;;; Window V:
2441;;; Between vc-locking-user and the following checkin (apparent state
2442;;; D). This window may never be closed if the user fails to complete the
2443;;; checkin message. Includes window R.
2444;;;
2445;;; Window W:
2446;;; Between vc-locking-user and the following steal-lock (apparent
34291cd2 2447;;; state E). This window may never close if the user fails to complete
594722a8
ER
2448;;; the steal-lock message. Includes window X.
2449;;;
2450;;; Window X:
2451;;; Between the unlock and the immediately following re-lock during a
2452;;; steal-lock operation (apparent state E). This window may never cloce
2453;;; if the user fails to complete the steal-lock message.
2454;;;
2455;;; Errors:
2456;;;
2457;;; Apparent state A ---
2458;;;
2459;;; 1. File looked unregistered but is actually registered and not locked.
2460;;;
2461;;; Potential cause: someone else's admin during window P, with
2462;;; caller's admin happening before their checkout.
2463;;;
b0c9bc8c
AS
2464;;; RCS: Prior to version 5.6.4, ci fails with message
2465;;; "no lock set by <user>". From 5.6.4 onwards, VC uses the new
2466;;; ci -i option and the message is "<file>,v: already exists".
594722a8
ER
2467;;; SCCS: admin will fail with error (ad19).
2468;;;
2469;;; We can let these errors be passed up to the user.
2470;;;
2471;;; 2. File looked unregistered but is actually locked by caller, unchanged.
2472;;;
2473;;; Potential cause: self-race during window P.
2474;;;
b0c9bc8c
AS
2475;;; RCS: Prior to version 5.6.4, reverts the file to the last saved
2476;;; version and unlocks it. From 5.6.4 onwards, VC uses the new
2477;;; ci -i option, failing with message "<file>,v: already exists".
594722a8
ER
2478;;; SCCS: will fail with error (ad19).
2479;;;
2480;;; Either of these consequences is acceptable.
2481;;;
2482;;; 3. File looked unregistered but is actually locked by caller, changed.
2483;;;
2484;;; Potential cause: self-race during window P.
2485;;;
b0c9bc8c
AS
2486;;; RCS: Prior to version 5.6.4, VC registers the caller's workfile as
2487;;; a delta with a null change comment (the -t- switch will be
2488;;; ignored). From 5.6.4 onwards, VC uses the new ci -i option,
2489;;; failing with message "<file>,v: already exists".
594722a8
ER
2490;;; SCCS: will fail with error (ad19).
2491;;;
2492;;; 4. File looked unregistered but is locked by someone else.
2493;;;
2494;;; Potential cause: someone else's admin during window P, with
2495;;; caller's admin happening *after* their checkout.
2496;;;
b0c9bc8c
AS
2497;;; RCS: Prior to version 5.6.4, ci fails with a
2498;;; "no lock set by <user>" message. From 5.6.4 onwards,
2499;;; VC uses the new ci -i option, failing with message
2500;;; "<file>,v: already exists".
594722a8
ER
2501;;; SCCS: will fail with error (ad19).
2502;;;
2503;;; We can let these errors be passed up to the user.
2504;;;
2505;;; Apparent state B ---
2506;;;
2507;;; 5. File looked registered and not locked, but is actually unregistered.
2508;;;
2509;;; Potential cause: master file got nuked during window P.
2510;;;
2511;;; RCS: will fail with "RCS/<file>: No such file or directory"
2512;;; SCCS: will fail with error ut4.
2513;;;
2514;;; We can let these errors be passed up to the user.
2515;;;
2516;;; 6. File looked registered and not locked, but is actually locked by the
2517;;; calling user and unchanged.
2518;;;
2519;;; Potential cause: self-race during window T.
2520;;;
2521;;; RCS: in the same directory as the previous workfile, co -l will fail
2522;;; with "co error: writable foo exists; checkout aborted". In any other
2523;;; directory, checkout will succeed.
2524;;; SCCS: will fail with ge17.
2525;;;
2526;;; Either of these consequences is acceptable.
2527;;;
2528;;; 7. File looked registered and not locked, but is actually locked by the
2529;;; calling user and changed.
2530;;;
2531;;; As case 6.
2532;;;
2533;;; 8. File looked registered and not locked, but is actually locked by another
2534;;; user.
2535;;;
2536;;; Potential cause: someone else checks it out during window T.
2537;;;
2538;;; RCS: co error: revision 1.3 already locked by <user>
2539;;; SCCS: fails with ge4 (in directory) or ut7 (outside it).
2540;;;
2541;;; We can let these errors be passed up to the user.
2542;;;
2543;;; Apparent state C ---
2544;;;
2545;;; 9. File looks locked by calling user and unchanged, but is unregistered.
2546;;;
2547;;; As case 5.
2548;;;
2549;;; 10. File looks locked by calling user and unchanged, but is actually not
2550;;; locked.
2551;;;
2552;;; Potential cause: a self-race in window U, or by the revert's
2553;;; landing during window X of some other user's steal-lock or window S
2554;;; of another user's revert.
2555;;;
2556;;; RCS: succeeds, refreshing the file from the identical version in
2557;;; the master.
2558;;; SCCS: fails with error ut4 (p file nonexistent).
2559;;;
2560;;; Either of these consequences is acceptable.
2561;;;
2562;;; 11. File is locked by calling user. It looks unchanged, but is actually
2563;;; changed.
2564;;;
2565;;; Potential cause: the file would have to be touched by a self-race
2566;;; during window Q.
2567;;;
2568;;; The revert will succeed, removing whatever changes came with
2569;;; the touch. It is theoretically possible that work could be lost.
2570;;;
2571;;; 12. File looks like it's locked by the calling user and unchanged, but
2572;;; it's actually locked by someone else.
2573;;;
2574;;; Potential cause: a steal-lock in window V.
2575;;;
2576;;; RCS: co error: revision <rev> locked by <user>; use co -r or rcs -u
2577;;; SCCS: fails with error un2
2578;;;
2579;;; We can pass these errors up to the user.
2580;;;
2581;;; Apparent state D ---
2582;;;
2583;;; 13. File looks like it's locked by the calling user and changed, but it's
2584;;; actually unregistered.
2585;;;
2586;;; Potential cause: master file got nuked during window P.
2587;;;
b0c9bc8c
AS
2588;;; RCS: Prior to version 5.6.4, checks in the user's version as an
2589;;; initial delta. From 5.6.4 onwards, VC uses the new ci -j
2590;;; option, failing with message "no such file or directory".
594722a8
ER
2591;;; SCCS: will fail with error ut4.
2592;;;
b0c9bc8c
AS
2593;;; This case is kind of nasty. Under RCS prior to version 5.6.4,
2594;;; VC may fail to detect the loss of previous version information.
594722a8
ER
2595;;;
2596;;; 14. File looks like it's locked by the calling user and changed, but it's
2597;;; actually unlocked.
2598;;;
2599;;; Potential cause: self-race in window V, or the checkin happening
2600;;; during the window X of someone else's steal-lock or window S of
2601;;; someone else's revert.
2602;;;
2603;;; RCS: ci will fail with "no lock set by <user>".
2604;;; SCCS: delta will fail with error ut4.
2605;;;
2606;;; 15. File looks like it's locked by the calling user and changed, but it's
2607;;; actually locked by the calling user and unchanged.
2608;;;
2609;;; Potential cause: another self-race --- a whole checkin/checkout
2610;;; sequence by the calling user would have to land in window R.
2611;;;
2612;;; SCCS: checks in a redundant delta and leaves the file unlocked as usual.
2613;;; RCS: reverts to the file state as of the second user's checkin, leaving
2614;;; the file unlocked.
2615;;;
2616;;; It is theoretically possible that work could be lost under RCS.
2617;;;
2618;;; 16. File looks like it's locked by the calling user and changed, but it's
2619;;; actually locked by a different user.
2620;;;
2621;;; RCS: ci error: no lock set by <user>
2622;;; SCCS: unget will fail with error un2
2623;;;
2624;;; We can pass these errors up to the user.
2625;;;
2626;;; Apparent state E ---
2627;;;
2628;;; 17. File looks like it's locked by some other user, but it's actually
2629;;; unregistered.
2630;;;
2631;;; As case 13.
2632;;;
2633;;; 18. File looks like it's locked by some other user, but it's actually
2634;;; unlocked.
2635;;;
2636;;; Potential cause: someone released a lock during window W.
2637;;;
2638;;; RCS: The calling user will get the lock on the file.
2639;;; SCCS: unget -n will fail with cm4.
2640;;;
2641;;; Either of these consequences will be OK.
2642;;;
2643;;; 19. File looks like it's locked by some other user, but it's actually
2644;;; locked by the calling user and unchanged.
2645;;;
2646;;; Potential cause: the other user relinquishing a lock followed by
2647;;; a self-race, both in window W.
2648;;;
2649;;; Under both RCS and SCCS, both unlock and lock will succeed, making
2650;;; the sequence a no-op.
2651;;;
2652;;; 20. File looks like it's locked by some other user, but it's actually
2653;;; locked by the calling user and changed.
2654;;;
2655;;; As case 19.
2656;;;
2657;;; PROBLEM CASES:
2658;;;
2659;;; In order of decreasing severity:
2660;;;
b0c9bc8c 2661;;; Cases 11 and 15 are the only ones that potentially lose work.
594722a8
ER
2662;;; They would require a self-race for this to happen.
2663;;;
2664;;; Case 13 in RCS loses information about previous deltas, retaining
2665;;; only the information in the current workfile. This can only happen
2666;;; if the master file gets nuked in window P.
2667;;;
2668;;; Case 3 in RCS and case 15 under SCCS insert a redundant delta with
2669;;; no change comment in the master. This would require a self-race in
2670;;; window P or R respectively.
2671;;;
2672;;; Cases 2, 10, 19 and 20 do extra work, but make no changes.
2673;;;
2674;;; Unfortunately, it appears to me that no recovery is possible in these
2675;;; cases. They don't yield error messages, so there's no way to tell that
2676;;; a race condition has occurred.
2677;;;
2678;;; All other cases don't change either the workfile or the master, and
2679;;; trigger command errors which the user will see.
2680;;;
2681;;; Thus, there is no explicit recovery code.
2682
2683;;; vc.el ends here