+(defun vc-cvs-get-entries (dir)
+ "Insert the CVS/Entries file from below DIR into the current buffer.
+This function ensures that the correct coding system is used for that,
+which may not be the one that is used for the files' contents.
+CVS/Entries should only be accessed through this function."
+ (let ((coding-system-for-read (or file-name-coding-system
+ default-file-name-coding-system)))
+ (vc-insert-file (expand-file-name "CVS/Entries" dir))))
+
+(defun vc-cvs-valid-symbolic-tag-name-p (tag)
+ "Return non-nil if TAG is a valid symbolic tag name."
+ ;; According to the CVS manual, a valid symbolic tag must start with
+ ;; an uppercase or lowercase letter and can contain uppercase and
+ ;; lowercase letters, digits, `-', and `_'.
+ (and (string-match "^[a-zA-Z]" tag)
+ (not (string-match "[^a-z0-9A-Z-_]" tag))))
+
+(defun vc-cvs-valid-version-number-p (tag)
+ "Return non-nil if TAG is a valid version number."
+ (and (string-match "^[0-9]" tag)
+ (not (string-match "[^0-9.]" tag))))
+
+(defun vc-cvs-parse-sticky-tag (match-type match-tag)
+ "Parse and return the sticky tag as a string.
+`match-data' is protected."
+ (let ((data (match-data))
+ (tag)
+ (type (cond ((string= match-type "D") 'date)
+ ((string= match-type "T")
+ (if (vc-cvs-valid-symbolic-tag-name-p match-tag)
+ 'symbolic-name
+ 'revision-number))
+ (t nil))))
+ (unwind-protect
+ (progn
+ (cond
+ ;; Sticky Date tag. Convert to a proper date value (`encode-time')
+ ((eq type 'date)
+ (string-match
+ "\\([0-9]+\\)\\.\\([0-9]+\\)\\.\\([0-9]+\\)\\.\\([0-9]+\\)\\.\\([0-9]+\\)\\.\\([0-9]+\\)"
+ match-tag)
+ (let* ((year-tmp (string-to-number (match-string 1 match-tag)))
+ (month (string-to-number (match-string 2 match-tag)))
+ (day (string-to-number (match-string 3 match-tag)))
+ (hour (string-to-number (match-string 4 match-tag)))
+ (min (string-to-number (match-string 5 match-tag)))
+ (sec (string-to-number (match-string 6 match-tag)))
+ ;; Years 0..68 are 2000..2068.
+ ;; Years 69..99 are 1969..1999.
+ (year (+ (cond ((> 69 year-tmp) 2000)
+ ((> 100 year-tmp) 1900)
+ (t 0))
+ year-tmp)))
+ (setq tag (encode-time sec min hour day month year))))
+ ;; Sticky Tag name or revision number
+ ((eq type 'symbolic-name) (setq tag match-tag))
+ ((eq type 'revision-number) (setq tag match-tag))
+ ;; Default is no sticky tag at all
+ (t nil))
+ (cond ((eq vc-cvs-sticky-tag-display nil) nil)
+ ((eq vc-cvs-sticky-tag-display t)
+ (cond ((eq type 'date) (format-time-string
+ vc-cvs-sticky-date-format-string
+ tag))
+ ((eq type 'symbolic-name) tag)
+ ((eq type 'revision-number) tag)
+ (t nil)))
+ ((functionp vc-cvs-sticky-tag-display)
+ (funcall vc-cvs-sticky-tag-display tag type))
+ (t nil)))
+
+ (set-match-data data))))
+