copyright.el 8.23 KB
Newer Older
1
;;; copyright.el --- update the copyright notice in current buffer
Eric S. Raymond's avatar
Eric S. Raymond committed
2

3
;; Copyright (C) 1991, 92, 93, 94, 95, 1998, 2001, 2003, 2004
4
;;           Free Software Foundation, Inc.
Eric S. Raymond's avatar
Eric S. Raymond committed
5

Karl Heuer's avatar
Karl Heuer committed
6
;; Author: Daniel Pfeiffer <occitan@esperanto.org>
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
;; Keywords: maint, tools

;; This file is part of GNU Emacs.

;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
Erik Naggum's avatar
Erik Naggum committed
22 23 24
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
25 26 27 28

;;; Commentary:

;; Allows updating the copyright year and above mentioned GPL version manually
29
;; or when saving a file.
Simon Josefsson's avatar
Simon Josefsson committed
30 31
;; Do (add-hook 'before-save-hook 'copyright-update), or use
;; M-x customize-variable RET before-save-hook RET.
Roland McGrath's avatar
Roland McGrath committed
32

Eric S. Raymond's avatar
Eric S. Raymond committed
33 34
;;; Code:

Andreas Schwab's avatar
Andreas Schwab committed
35 36 37 38 39
(defgroup copyright nil
  "Update the copyright notice in current buffer."
  :group 'tools)

(defcustom copyright-limit 2000
40
  "*Don't try to update copyright beyond this position unless interactive.
41
A value of nil means to search whole buffer."
Andreas Schwab's avatar
Andreas Schwab committed
42 43 44
  :group 'copyright
  :type '(choice (integer :tag "Limit")
		 (const :tag "No limit")))
45

Dave Love's avatar
Dave Love committed
46 47
;; The character classes have the Latin-1 version and the Latin-9
;; version, which is probably enough.
Andreas Schwab's avatar
Andreas Schwab committed
48
(defcustom copyright-regexp
49 50
 "\\([©Ž©]\\|@copyright{}\\|[Cc]opyright\\s *:?\\s *\\(?:(C)\\)?\
\\|[Cc]opyright\\s *:?\\s *[©Ž©]\\)\
Karl Berry's avatar
Karl Berry committed
51
\\s *\\([1-9]\\([-0-9, ';/*%#\n\t]\\|\\s<\\|\\s>\\)*[0-9]+\\)"
52
  "*What your copyright notice looks like.
Andreas Schwab's avatar
Andreas Schwab committed
53 54 55
The second \\( \\) construct must match the years."
  :group 'copyright
  :type 'regexp)
56

57 58 59 60 61 62 63
(defcustom copyright-years-regexp
 "\\(\\s *\\)\\([1-9]\\([-0-9, ';/*%#\n\t]\\|\\s<\\|\\s>\\)*[0-9]+\\)"
  "*Match additional copyright notice years.
The second \\( \\) construct must match the years."
  :group 'copyright
  :type 'regexp)

64

Andreas Schwab's avatar
Andreas Schwab committed
65
(defcustom copyright-query 'function
66
  "*If non-nil, ask user before changing copyright.
Andreas Schwab's avatar
Andreas Schwab committed
67 68 69
When this is `function', only ask when called non-interactively."
  :group 'copyright
  :type '(choice (const :tag "Do not ask")
70 71
		 (const :tag "Ask unless interactive" function)
		 (other :tag "Ask" t)))
72 73


Karl Heuer's avatar
Karl Heuer committed
74
;; when modifying this, also modify the comment generated by autoinsert.el
75
(defconst copyright-current-gpl-version "2"
76
  "String representing the current version of the GPL or nil.")
Roland McGrath's avatar
Roland McGrath committed
77

78
(defvar copyright-update t)
Roland McGrath's avatar
Roland McGrath committed
79

80 81
;; This is a defvar rather than a defconst, because the year can
;; change during the Emacs session.
82
(defvar copyright-current-year (substring (current-time-string) -4)
83 84
  "String representing the current year.")

85 86
(defun copyright-update-year (replace noquery)
  (when (re-search-forward copyright-regexp (+ (point) copyright-limit) t)
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
    ;; If the years are continued onto multiple lined
    ;; that are marked as comments, skip to the end of the years anyway.
    (while (save-excursion
	     (and (eq (following-char) ?,)
		  (progn (forward-char 1) t)
		  (progn (skip-chars-forward " \t") (eolp))
		  comment-start-skip
		  (save-match-data
		    (forward-line 1)
		    (and (looking-at comment-start-skip)
			 (goto-char (match-end 0))))
		  (save-match-data
		    (looking-at copyright-years-regexp))))
      (forward-line 1)
      (re-search-forward comment-start-skip)
      (re-search-forward copyright-years-regexp))
103

104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
    ;; Note that `current-time-string' isn't locale-sensitive.
    (setq copyright-current-year (substring (current-time-string) -4))
    (unless (string= (buffer-substring (- (match-end 2) 2) (match-end 2))
		     (substring copyright-current-year -2))
      (if (or noquery
	      (y-or-n-p (if replace
			    (concat "Replace copyright year(s) by "
				    copyright-current-year "? ")
			  (concat "Add " copyright-current-year
				  " to copyright? "))))
	  (if replace
	      (replace-match copyright-current-year t t nil 1)
	    (let ((size (save-excursion (skip-chars-backward "0-9"))))
	      (if (and (eq (% (- (string-to-number copyright-current-year)
				 (string-to-number (buffer-substring
						    (+ (point) size)
						    (point))))
			      100)
			   1)
		       (or (eq (char-after (+ (point) size -1)) ?-)
			   (eq (char-after (+ (point) size -2)) ?-)))
		  ;; This is a range so just replace the end part.
		  (delete-char size)
		;; Insert a comma with the preferred number of spaces.
		(insert
		 (save-excursion
		   (if (re-search-backward "[0-9]\\( *, *\\)[0-9]"
					   (line-beginning-position) t)
		       (match-string 1)
		     ", ")))
		;; If people use the '91 '92 '93 scheme, do that as well.
		(if (eq (char-after (+ (point) size -3)) ?')
		    (insert ?')))
	      ;; Finally insert the new year.
	      (insert (substring copyright-current-year size))))))))
139

Roland McGrath's avatar
Roland McGrath committed
140
;;;###autoload
141
(defun copyright-update (&optional arg interactivep)
142 143 144 145
  "Update copyright notice at beginning of buffer to indicate the current year.
With prefix ARG, replace the years in the notice rather than adding
the current year after them.  If necessary, and
`copyright-current-gpl-version' is set, any copying permissions
146 147 148 149 150 151 152
following the copyright are updated as well.
If non-nil, INTERACTIVEP tells the function to behave as when it's called
interactively."
  (interactive "*P\nd")
  (when (or copyright-update interactivep)
    (let ((noquery (or (not copyright-query)
		       (and (eq copyright-query 'function) interactivep))))
153 154 155 156
      (save-excursion
	(save-restriction
	  (widen)
	  (goto-char (point-min))
157
	  (copyright-update-year arg noquery)
158 159 160 161
	  (goto-char (point-min))
	  (and copyright-current-gpl-version
	       ;; match the GPL version comment in .el files, including the
	       ;; bilingual Esperanto one in two-column, and in texinfo.tex
162 163 164
	       (re-search-forward "\\(the Free Software Foundation;\
 either \\|; a\\^u eldono \\([0-9]+\\)a, ? a\\^u (la\\^u via	 \\)\
version \\([0-9]+\\), or (at"
165
				  (+ (point) copyright-limit) t)
166
	       (not (string= (match-string 3) copyright-current-gpl-version))
167
	       (or noquery
168 169 170 171 172
		   (y-or-n-p (concat "Replace GPL version by "
				     copyright-current-gpl-version "? ")))
	       (progn
		 (if (match-end 2)
		     ;; Esperanto bilingual comment in two-column.el
173 174
		     (replace-match copyright-current-gpl-version t t nil 2))
		 (replace-match copyright-current-gpl-version t t nil 3))))
175
	(set (make-local-variable 'copyright-update) nil)))
176 177
    ;; If a write-file-hook returns non-nil, the file is presumed to be written.
    nil))
Roland McGrath's avatar
Roland McGrath committed
178

Eric S. Raymond's avatar
Eric S. Raymond committed
179

180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
;;;###autoload
(defun copyright-fix-years ()
  "Convert 2 digit years to 4 digit years.
Uses heuristic: year >= 50 means 19xx, < 50 means 20xx."
  (interactive)
  (widen)
  (goto-char (point-min))
  (if (re-search-forward copyright-regexp (+ (point) copyright-limit) t)
      (let ((s (match-beginning 2)) (e (make-marker))
	    last)
	(set-marker e (1+ (match-end 2)))
	(goto-char s)
	(while (and (< (point) (marker-position e))
		    (re-search-forward "\\([^0-9]\\)\\([0-9]+\\)[^0-9]"
				       (marker-position e) t))
	  (let ((p (point))
		(sep (match-string 1))
		(year (string-to-number (match-string 2))))
	    (goto-char (1+ (match-beginning 0)))
	    (unless (= (char-syntax (string-to-char sep)) ?\s)
	      (insert " "))
	    (if (< year 100)
		(insert (if (>= year 50) "19" "20")))
	    (goto-char p)
	    (setq last p)))
	(when last
	  (goto-char last)
	  (let ((fill-prefix "     "))
	    (fill-region s last))
	  )
	(set-marker e nil)
	(copyright-update nil t))
    (message "No copyright message")
    (goto-char (point-min))))

215 216 217 218 219
;;;###autoload
(define-skeleton copyright
  "Insert a copyright by $ORGANIZATION notice at cursor."
  "Company: "
  comment-start
220
  "Copyright (C) " `(substring (current-time-string) -4) " by "
221 222
  (or (getenv "ORGANIZATION")
      str)
223
  '(if (> (point) (+ (point-min) copyright-limit))
224
       (message "Copyright extends beyond `copyright-limit' and won't be updated automatically."))
Stefan Monnier's avatar
Stefan Monnier committed
225
  comment-end \n)
226

Richard M. Stallman's avatar
Richard M. Stallman committed
227 228
(provide 'copyright)

Dave Love's avatar
Dave Love committed
229 230 231 232 233
;; For the copyright sign:
;; Local Variables:
;; coding: emacs-mule
;; End:

Miles Bader's avatar
Miles Bader committed
234
;;; arch-tag: b4991afb-b6b1-4590-bebe-e076d9d4aee8
235
;;; copyright.el ends here