Switch to recommended form of GPLv3 permissions notice.
[bpt/emacs.git] / lisp / emacs-lisp / copyright.el
CommitLineData
3f61a2e7 1;;; copyright.el --- update the copyright notice in current buffer
d501f516 2
3731a850 3;; Copyright (C) 1991, 1992, 1993, 1994, 1995, 1998, 2001, 2002, 2003,
8b72699e 4;; 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
58142744 5
3e910376 6;; Author: Daniel Pfeiffer <occitan@esperanto.org>
3f61a2e7
KH
7;; Keywords: maint, tools
8
9;; This file is part of GNU Emacs.
10
d6cba7ae 11;; GNU Emacs is free software: you can redistribute it and/or modify
3f61a2e7 12;; it under the terms of the GNU General Public License as published by
d6cba7ae
GM
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) any later version.
3f61a2e7
KH
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
d6cba7ae 22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
3f61a2e7
KH
23
24;;; Commentary:
25
26;; Allows updating the copyright year and above mentioned GPL version manually
f47f5302 27;; or when saving a file.
6b61353c
KH
28;; Do (add-hook 'before-save-hook 'copyright-update), or use
29;; M-x customize-variable RET before-save-hook RET.
0343b087 30
d46bac56
ER
31;;; Code:
32
3f251fcd
AS
33(defgroup copyright nil
34 "Update the copyright notice in current buffer."
35 :group 'tools)
36
37(defcustom copyright-limit 2000
b649d2e4 38 "Don't try to update copyright beyond this position unless interactive.
9c05459c 39A value of nil means to search whole buffer."
3f251fcd
AS
40 :group 'copyright
41 :type '(choice (integer :tag "Limit")
42 (const :tag "No limit")))
3f61a2e7 43
b2c7c56d
GM
44(defcustom copyright-at-end-flag nil
45 "Non-nil means to search backwards from the end of the buffer for copyright.
46This is useful for ChangeLogs."
47 :group 'copyright
48 :type 'boolean
49 :version "23.1")
50
3f251fcd 51(defcustom copyright-regexp
e145a7fe 52 "\\(©\\|@copyright{}\\|[Cc]opyright\\s *:?\\s *\\(?:(C)\\)?\
d260b218 53\\|[Cc]opyright\\s *:?\\s *©\\)\
2e3b4a0b 54\\s *\\([1-9]\\([-0-9, ';/*%#\n\t]\\|\\s<\\|\\s>\\)*[0-9]+\\)"
b649d2e4 55 "What your copyright notice looks like.
3f251fcd
AS
56The second \\( \\) construct must match the years."
57 :group 'copyright
58 :type 'regexp)
3f61a2e7 59
b649d2e4
SM
60(defcustom copyright-names-regexp ""
61 "Regexp matching the names which correspond to the user.
62Only copyright lines where the name matches this regexp will be updated.
8a1dd108 63This allows you to avoid adding years to a copyright notice belonging to
b649d2e4 64someone else or to a group for which you do not work."
44168837 65 :group 'copyright
b649d2e4
SM
66 :type 'regexp)
67
69311816
RS
68(defcustom copyright-years-regexp
69 "\\(\\s *\\)\\([1-9]\\([-0-9, ';/*%#\n\t]\\|\\s<\\|\\s>\\)*[0-9]+\\)"
b649d2e4 70 "Match additional copyright notice years.
69311816
RS
71The second \\( \\) construct must match the years."
72 :group 'copyright
73 :type 'regexp)
74
3f61a2e7 75
3f251fcd 76(defcustom copyright-query 'function
b649d2e4 77 "If non-nil, ask user before changing copyright.
3f251fcd
AS
78When this is `function', only ask when called non-interactively."
79 :group 'copyright
80 :type '(choice (const :tag "Do not ask")
e4f0bdfa
AS
81 (const :tag "Ask unless interactive" function)
82 (other :tag "Ask" t)))
3f61a2e7
KH
83
84
a7acbbe4 85;; when modifying this, also modify the comment generated by autoinsert.el
948d9b97 86(defconst copyright-current-gpl-version "3"
9c05459c 87 "String representing the current version of the GPL or nil.")
0343b087 88
3f61a2e7 89(defvar copyright-update t)
9cfd2eeb 90
b7812d30
EZ
91;; This is a defvar rather than a defconst, because the year can
92;; change during the Emacs session.
9c05459c 93(defvar copyright-current-year (substring (current-time-string) -4)
b7812d30
EZ
94 "String representing the current year.")
95
4168d2c7 96(defsubst copyright-limit () ; re-search-forward BOUND
b2c7c56d
GM
97 (and copyright-limit
98 (if copyright-at-end-flag
99 (- (point) copyright-limit)
100 (+ (point) copyright-limit))))
101
102(defun copyright-re-search (regexp &optional bound noerror count)
103 "Re-search forward or backward depending on `copyright-at-end-flag'."
104 (if copyright-at-end-flag
105 (re-search-backward regexp bound noerror count)
106 (re-search-forward regexp bound noerror count)))
107
108(defun copyright-start-point ()
109 "Return point-min or point-max, depending on `copyright-at-end-flag'."
110 (if copyright-at-end-flag
111 (point-max)
112 (point-min)))
113
114(defun copyright-offset-too-large-p ()
115 "Return non-nil if point is too far from the edge of the buffer."
116 (when copyright-limit
117 (if copyright-at-end-flag
118 (< (point) (- (point-max) copyright-limit))
119 (> (point) (+ (point-min) copyright-limit)))))
4168d2c7 120
f47f5302 121(defun copyright-update-year (replace noquery)
b649d2e4
SM
122 (when
123 (condition-case err
ce12d620
GM
124 ;; (1) Need the extra \\( \\) around copyright-regexp because we
125 ;; goto (match-end 1) below. See note (2) below.
b2c7c56d
GM
126 (copyright-re-search (concat "\\(" copyright-regexp
127 "\\)\\([ \t]*\n\\)?.*\\(?:"
128 copyright-names-regexp "\\)")
129 (copyright-limit)
130 t)
b649d2e4
SM
131 ;; In case the regexp is rejected. This is useful because
132 ;; copyright-update is typically called from before-save-hook where
133 ;; such an error is very inconvenient for the user.
134 (error (message "Can't update copyright: %s" err) nil))
135 (goto-char (match-end 1))
ce12d620 136 ;; If the years are continued onto multiple lines
69311816
RS
137 ;; that are marked as comments, skip to the end of the years anyway.
138 (while (save-excursion
139 (and (eq (following-char) ?,)
140 (progn (forward-char 1) t)
141 (progn (skip-chars-forward " \t") (eolp))
142 comment-start-skip
80817d7b 143 (save-match-data
69311816 144 (forward-line 1)
80817d7b 145 (and (looking-at comment-start-skip)
f5e087f8 146 (goto-char (match-end 0))))
68af6bd6 147 (looking-at-p copyright-years-regexp)))
69311816
RS
148 (forward-line 1)
149 (re-search-forward comment-start-skip)
ce12d620
GM
150 ;; (2) Need the extra \\( \\) so that the years are subexp 3, as
151 ;; they are at note (1) above.
152 (re-search-forward (format "\\(%s\\)" copyright-years-regexp)))
697f502a 153
f47f5302
SM
154 ;; Note that `current-time-string' isn't locale-sensitive.
155 (setq copyright-current-year (substring (current-time-string) -4))
b649d2e4 156 (unless (string= (buffer-substring (- (match-end 3) 2) (match-end 3))
f47f5302
SM
157 (substring copyright-current-year -2))
158 (if (or noquery
159 (y-or-n-p (if replace
160 (concat "Replace copyright year(s) by "
161 copyright-current-year "? ")
162 (concat "Add " copyright-current-year
163 " to copyright? "))))
164 (if replace
ce12d620 165 (replace-match copyright-current-year t t nil 3)
f47f5302
SM
166 (let ((size (save-excursion (skip-chars-backward "0-9"))))
167 (if (and (eq (% (- (string-to-number copyright-current-year)
168 (string-to-number (buffer-substring
169 (+ (point) size)
170 (point))))
171 100)
172 1)
173 (or (eq (char-after (+ (point) size -1)) ?-)
174 (eq (char-after (+ (point) size -2)) ?-)))
175 ;; This is a range so just replace the end part.
176 (delete-char size)
f47f5302
SM
177 ;; Insert a comma with the preferred number of spaces.
178 (insert
179 (save-excursion
180 (if (re-search-backward "[0-9]\\( *, *\\)[0-9]"
181 (line-beginning-position) t)
182 (match-string 1)
183 ", ")))
184 ;; If people use the '91 '92 '93 scheme, do that as well.
185 (if (eq (char-after (+ (point) size -3)) ?')
186 (insert ?')))
187 ;; Finally insert the new year.
188 (insert (substring copyright-current-year size))))))))
b7812d30 189
0343b087 190;;;###autoload
f47f5302 191(defun copyright-update (&optional arg interactivep)
9c05459c
RS
192 "Update copyright notice at beginning of buffer to indicate the current year.
193With prefix ARG, replace the years in the notice rather than adding
194the current year after them. If necessary, and
195`copyright-current-gpl-version' is set, any copying permissions
f47f5302
SM
196following the copyright are updated as well.
197If non-nil, INTERACTIVEP tells the function to behave as when it's called
198interactively."
199 (interactive "*P\nd")
200 (when (or copyright-update interactivep)
201 (let ((noquery (or (not copyright-query)
202 (and (eq copyright-query 'function) interactivep))))
3f61a2e7
KH
203 (save-excursion
204 (save-restriction
205 (widen)
b2c7c56d 206 (goto-char (copyright-start-point))
f47f5302 207 (copyright-update-year arg noquery)
b2c7c56d 208 (goto-char (copyright-start-point))
3f61a2e7
KH
209 (and copyright-current-gpl-version
210 ;; match the GPL version comment in .el files, including the
211 ;; bilingual Esperanto one in two-column, and in texinfo.tex
b2c7c56d 212 (copyright-re-search
463dca7e 213 "\\(the Free Software Foundation;\
9c05459c
RS
214 either \\|; a\\^u eldono \\([0-9]+\\)a, ? a\\^u (la\\^u via \\)\
215version \\([0-9]+\\), or (at"
4168d2c7 216 (copyright-limit) t)
2cb250dd
SM
217 ;; Don't update if the file is already using a more recent
218 ;; version than the "current" one.
219 (< (string-to-number (match-string 3))
220 (string-to-number copyright-current-gpl-version))
f47f5302 221 (or noquery
2cb250dd
SM
222 (y-or-n-p (format "Replace GPL version by %s? "
223 copyright-current-gpl-version)))
3f61a2e7
KH
224 (progn
225 (if (match-end 2)
226 ;; Esperanto bilingual comment in two-column.el
f47f5302
SM
227 (replace-match copyright-current-gpl-version t t nil 2))
228 (replace-match copyright-current-gpl-version t t nil 3))))
3f61a2e7 229 (set (make-local-variable 'copyright-update) nil)))
f47f5302
SM
230 ;; If a write-file-hook returns non-nil, the file is presumed to be written.
231 nil))
0343b087 232
d501f516 233
422032f0
KS
234;;;###autoload
235(defun copyright-fix-years ()
236 "Convert 2 digit years to 4 digit years.
237Uses heuristic: year >= 50 means 19xx, < 50 means 20xx."
238 (interactive)
239 (widen)
b2c7c56d
GM
240 (goto-char (copyright-start-point))
241 (if (copyright-re-search copyright-regexp (copyright-limit) t)
07b41c42
LK
242 (let ((s (match-beginning 2))
243 (e (copy-marker (1+ (match-end 2))))
244 (p (make-marker))
422032f0 245 last)
422032f0 246 (goto-char s)
07b41c42
LK
247 (while (re-search-forward "[0-9]+" e t)
248 (set-marker p (point))
249 (goto-char (match-beginning 0))
250 (let ((sep (char-before))
251 (year (string-to-number (match-string 0))))
252 (when (and sep
253 (/= (char-syntax sep) ?\s)
254 (/= sep ?-))
422032f0 255 (insert " "))
07b41c42
LK
256 (when (< year 100)
257 (insert (if (>= year 50) "19" "20"))))
258 (goto-char p)
259 (setq last p))
422032f0
KS
260 (when last
261 (goto-char last)
02d9d682
RS
262 ;; Don't mess up whitespace after the years.
263 (skip-chars-backward " \t")
264 (save-restriction
b2c7c56d 265 (narrow-to-region (copyright-start-point) (point))
02d9d682 266 (let ((fill-prefix " "))
07b41c42 267 (fill-region s last))))
422032f0 268 (set-marker e nil)
07b41c42 269 (set-marker p nil)
422032f0 270 (copyright-update nil t))
07b41c42 271 (message "No copyright message")))
422032f0 272
3f61a2e7
KH
273;;;###autoload
274(define-skeleton copyright
275 "Insert a copyright by $ORGANIZATION notice at cursor."
276 "Company: "
277 comment-start
b7812d30 278 "Copyright (C) " `(substring (current-time-string) -4) " by "
3f61a2e7
KH
279 (or (getenv "ORGANIZATION")
280 str)
b2c7c56d 281 '(if (copyright-offset-too-large-p)
3f61a2e7 282 (message "Copyright extends beyond `copyright-limit' and won't be updated automatically."))
48a96f51 283 comment-end \n)
3f61a2e7 284
470fc354
RS
285(defun copyright-update-directory (directory match)
286 "Update copyright notice for all files in DIRECTORY matching MATCH."
287 (interactive "DDirectory: \nMFilenames matching: ")
288 (dolist (file (directory-files directory t match nil))
289 (find-file file)
290 (let ((copyright-query nil))
291 (copyright-update))
292 (save-buffer)
293 (kill-buffer (current-buffer))))
294
896546cd
RS
295(provide 'copyright)
296
bf5f1abd
DL
297;; For the copyright sign:
298;; Local Variables:
d260b218 299;; coding: utf-8
bf5f1abd
DL
300;; End:
301
b649d2e4 302;; arch-tag: b4991afb-b6b1-4590-bebe-e076d9d4aee8
e8af40ee 303;;; copyright.el ends here