Sync to HEAD
[bpt/emacs.git] / lisp / emacs-lisp / copyright.el
CommitLineData
3f61a2e7 1;;; copyright.el --- update the copyright notice in current buffer
d501f516 2
6b61353c 3;; Copyright (C) 1991, 92, 93, 94, 95, 1998, 2001, 2003, 2004
f47f5302 4;; 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
13;; the Free Software Foundation; either version 2, or (at your option)
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
EN
22;; along with GNU Emacs; see the file COPYING. If not, write to the
23;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24;; Boston, MA 02111-1307, 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
3f61a2e7 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
8f924df7 47 "\\(©\|@copyright{}\\|[Cc]opyright\\s *:?\\s *\\(?:(C)\\)?\
d260b218 48\\|[Cc]opyright\\s *:?\\s *©\\)\
9c05459c 49\\s *\\([1-9]\\([-0-9, ';\n\t]\\|\\s<\\|\\s>\\)*[0-9]+\\)"
3f61a2e7 50 "*What your copyright notice looks like.
3f251fcd
AS
51The second \\( \\) construct must match the years."
52 :group 'copyright
53 :type 'regexp)
3f61a2e7
KH
54
55
3f251fcd 56(defcustom copyright-query 'function
9c05459c 57 "*If non-nil, ask user before changing copyright.
3f251fcd
AS
58When this is `function', only ask when called non-interactively."
59 :group 'copyright
60 :type '(choice (const :tag "Do not ask")
e4f0bdfa
AS
61 (const :tag "Ask unless interactive" function)
62 (other :tag "Ask" t)))
3f61a2e7
KH
63
64
a7acbbe4 65;; when modifying this, also modify the comment generated by autoinsert.el
3f61a2e7 66(defconst copyright-current-gpl-version "2"
9c05459c 67 "String representing the current version of the GPL or nil.")
0343b087 68
3f61a2e7 69(defvar copyright-update t)
9cfd2eeb 70
b7812d30
EZ
71;; This is a defvar rather than a defconst, because the year can
72;; change during the Emacs session.
9c05459c 73(defvar copyright-current-year (substring (current-time-string) -4)
b7812d30
EZ
74 "String representing the current year.")
75
f47f5302
SM
76(defun copyright-update-year (replace noquery)
77 (when (re-search-forward copyright-regexp (+ (point) copyright-limit) t)
78 ;; Note that `current-time-string' isn't locale-sensitive.
79 (setq copyright-current-year (substring (current-time-string) -4))
80 (unless (string= (buffer-substring (- (match-end 2) 2) (match-end 2))
81 (substring copyright-current-year -2))
82 (if (or noquery
83 (y-or-n-p (if replace
84 (concat "Replace copyright year(s) by "
85 copyright-current-year "? ")
86 (concat "Add " copyright-current-year
87 " to copyright? "))))
88 (if replace
89 (replace-match copyright-current-year t t nil 1)
90 (let ((size (save-excursion (skip-chars-backward "0-9"))))
91 (if (and (eq (% (- (string-to-number copyright-current-year)
92 (string-to-number (buffer-substring
93 (+ (point) size)
94 (point))))
95 100)
96 1)
97 (or (eq (char-after (+ (point) size -1)) ?-)
98 (eq (char-after (+ (point) size -2)) ?-)))
99 ;; This is a range so just replace the end part.
100 (delete-char size)
101 ;; Detect if this is using the following shorthand:
102 ;; (C) 1993, 94, 95, 1998, 2000, 01, 02, 2003
103 (if (and
104 ;; Check that the last year was 4-chars and same century.
105 (eq size -4)
106 (equal (buffer-substring (- (point) 4) (- (point) 2))
107 (substring copyright-current-year 0 2))
108 ;; Check that there are 2-char years as well.
109 (save-excursion
110 (re-search-backward "[^0-9][0-9][0-9][^0-9]"
111 (line-beginning-position) t))
112 ;; Make sure we don't remove the first century marker.
113 (save-excursion
114 (forward-char size)
115 (re-search-backward
116 (concat (buffer-substring (point) (+ (point) 2))
117 "[0-9][0-9]")
118 (line-beginning-position) t)))
119 ;; Remove the century marker of the last entry.
120 (delete-region (- (point) 4) (- (point) 2)))
121 ;; Insert a comma with the preferred number of spaces.
122 (insert
123 (save-excursion
124 (if (re-search-backward "[0-9]\\( *, *\\)[0-9]"
125 (line-beginning-position) t)
126 (match-string 1)
127 ", ")))
128 ;; If people use the '91 '92 '93 scheme, do that as well.
129 (if (eq (char-after (+ (point) size -3)) ?')
130 (insert ?')))
131 ;; Finally insert the new year.
132 (insert (substring copyright-current-year size))))))))
b7812d30 133
0343b087 134;;;###autoload
f47f5302 135(defun copyright-update (&optional arg interactivep)
9c05459c
RS
136 "Update copyright notice at beginning of buffer to indicate the current year.
137With prefix ARG, replace the years in the notice rather than adding
138the current year after them. If necessary, and
139`copyright-current-gpl-version' is set, any copying permissions
f47f5302
SM
140following the copyright are updated as well.
141If non-nil, INTERACTIVEP tells the function to behave as when it's called
142interactively."
143 (interactive "*P\nd")
144 (when (or copyright-update interactivep)
145 (let ((noquery (or (not copyright-query)
146 (and (eq copyright-query 'function) interactivep))))
3f61a2e7
KH
147 (save-excursion
148 (save-restriction
149 (widen)
150 (goto-char (point-min))
f47f5302 151 (copyright-update-year arg noquery)
3f61a2e7
KH
152 (goto-char (point-min))
153 (and copyright-current-gpl-version
154 ;; match the GPL version comment in .el files, including the
155 ;; bilingual Esperanto one in two-column, and in texinfo.tex
9c05459c
RS
156 (re-search-forward "\\(the Free Software Foundation;\
157 either \\|; a\\^u eldono \\([0-9]+\\)a, ? a\\^u (la\\^u via \\)\
158version \\([0-9]+\\), or (at"
f47f5302 159 (+ (point) copyright-limit) t)
9c05459c 160 (not (string= (match-string 3) copyright-current-gpl-version))
f47f5302 161 (or noquery
3f61a2e7
KH
162 (y-or-n-p (concat "Replace GPL version by "
163 copyright-current-gpl-version "? ")))
164 (progn
165 (if (match-end 2)
166 ;; Esperanto bilingual comment in two-column.el
f47f5302
SM
167 (replace-match copyright-current-gpl-version t t nil 2))
168 (replace-match copyright-current-gpl-version t t nil 3))))
3f61a2e7 169 (set (make-local-variable 'copyright-update) nil)))
f47f5302
SM
170 ;; If a write-file-hook returns non-nil, the file is presumed to be written.
171 nil))
0343b087 172
d501f516 173
3f61a2e7
KH
174;;;###autoload
175(define-skeleton copyright
176 "Insert a copyright by $ORGANIZATION notice at cursor."
177 "Company: "
178 comment-start
b7812d30 179 "Copyright (C) " `(substring (current-time-string) -4) " by "
3f61a2e7
KH
180 (or (getenv "ORGANIZATION")
181 str)
f47f5302 182 '(if (> (point) (+ (point-min) copyright-limit))
3f61a2e7 183 (message "Copyright extends beyond `copyright-limit' and won't be updated automatically."))
48a96f51 184 comment-end \n)
3f61a2e7 185
896546cd
RS
186(provide 'copyright)
187
bf5f1abd
DL
188;; For the copyright sign:
189;; Local Variables:
d260b218 190;; coding: utf-8
bf5f1abd
DL
191;; End:
192
6b61353c 193;;; arch-tag: b4991afb-b6b1-4590-bebe-e076d9d4aee8
e8af40ee 194;;; copyright.el ends here