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