(webjump-sample-sites): Change the hot list.
[bpt/emacs.git] / lisp / time-stamp.el
CommitLineData
9565745a 1;;; time-stamp.el --- Maintain last change time stamps in files edited by Emacs
9565745a 2
b578f267
EN
3;; Copyright 1989, 1993, 1994, 1995 Free Software Foundation, Inc.
4
622b7ede
RS
5;; Maintainer's Time-stamp: <1997-04-28 11:51:22 gildea>
6;; Maintainer: Stephen Gildea <gildea@alum.mit.edu>
9565745a
RS
7;; Keywords: tools
8
9;; This file is free software; you can redistribute it and/or modify
10;; it under the terms of the GNU General Public License as published by
11;; the Free Software Foundation; either version 2, or (at your option)
12;; any later version.
13
14;; This file is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
b578f267
EN
20;; along with GNU Emacs; see the file COPYING. If not, write to the
21;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22;; Boston, MA 02111-1307, USA.
9565745a
RS
23
24;;; Commentary:
25
03d7856a
KH
26;; A template in a file can be updated with a new time stamp when
27;; you save the file. For example:
28;; static char *ts = "sdmain.c Time-stamp: <1996-08-13 10:20:51 gildea>";
29;; See the top of `time-stamp.el' for another example.
30
31;; To use time-stamping, add this line to your .emacs file:
32;; (add-hook 'write-file-hooks 'time-stamp)
33;; Now any time-stamp templates in your files will be updated automatically.
34
35;; See the documentation for the functions `time-stamp'
36;; and `time-stamp-toggle-active' for details.
b578f267 37
9565745a
RS
38;;; Code:
39
cb35a83c
RS
40(defgroup time-stamp nil
41 "Maintain last change time stamps in files edited by Emacs."
42 :group 'data
43 :group 'extensions)
44
45(defcustom time-stamp-active t
f8d35bf3 46 "*Non-nil to enable time-stamping of buffers by \\[time-stamp].
b1defad2 47Can be toggled by \\[time-stamp-toggle-active].
cb35a83c
RS
48See also the variable `time-stamp-warn-inactive'."
49 :type 'boolean
50 :group 'time-stamp)
b1defad2 51
cb35a83c 52(defcustom time-stamp-warn-inactive t
03d7856a
KH
53 "Non-nil to have \\[time-stamp] warn if a buffer did not get time-stamped.
54A warning is printed if `time-stamp-active' is nil and the buffer contains
cb35a83c
RS
55a time stamp template that would otherwise have been updated."
56 :type 'boolean
57 :group 'time-stamp)
b1defad2 58
cb35a83c 59(defcustom time-stamp-old-format-warn 'ask
03d7856a 60 "Action to take if `time-stamp-format' is an old-style list.
c9c0e4bb
RS
61If `error', the format is not used. If `ask', the user is queried about
62using the time-stamp-format. If `warn', a warning is displayed.
cb35a83c 63If nil, no notification is given."
622b7ede 64 :type '(choice (const :tag "No notification" nil)
cb35a83c
RS
65 (const :tag "Don't use the format" error)
66 (const ask) (const warn))
67 :group 'time-stamp)
03d7856a 68
622b7ede 69(defcustom time-stamp-format "%Y-%02m-%02d %02H:%02M:%02S %u"
03d7856a 70 "*Format of the string inserted by \\[time-stamp].
c9c0e4bb
RS
71The value may be a string or a list. Lists are supported only for
72backward compatibility; see variable `time-stamp-old-format-warn'.
f8d35bf3 73
c9c0e4bb 74A string is used with `format-time-string'.
6946129c
RS
75In addition to the features of `format-time-string',
76you can use the following %-constructs:
77
78%f file name without directory
79%F full file name
80%h mail host name
81%s system name
622b7ede
RS
82%u user's login name
83
84For example, to get the format used by the `date' command,
85use \"%3a %3b %2d %02H:%02M:%02S %Z %Y\"."
cb35a83c
RS
86 :type 'string
87 :group 'time-stamp)
03d7856a 88
622b7ede
RS
89
90
9565745a
RS
91;;; Do not change time-stamp-line-limit, time-stamp-start, or
92;;; time-stamp-end in your .emacs or you will be incompatible
93;;; with other people's files! If you must change them,
94;;; do so only in the local variables section of the file itself.
95
03d7856a 96
e1f40b28 97(defvar time-stamp-line-limit 8 ;Do not change!
c7c4ddd4 98 "Lines of a file searched; positive counts from start, negative from end.
e1f40b28 99The patterns `time-stamp-start' and `time-stamp-end' must be found on one
c7c4ddd4
KH
100of the first (last) `time-stamp-line-limit' lines of the file for the
101file to be time-stamped by \\[time-stamp].
e1f40b28
RS
102
103Do not change `time-stamp-line-limit', `time-stamp-start', or
104`time-stamp-end' for yourself or you will be incompatible
105with other people's files! If you must change them for some application,
106do so in the local variables section of the time-stamped file itself.")
107
9565745a 108
36081614 109(defvar time-stamp-start "Time-stamp:[ \t]+\\\\?[\"<]+" ;Do not change!
9565745a 110 "Regexp after which the time stamp is written by \\[time-stamp].
e1f40b28 111See also the variables `time-stamp-end' and `time-stamp-line-limit'.
9565745a 112
e1f40b28
RS
113Do not change `time-stamp-line-limit', `time-stamp-start', or
114`time-stamp-end' for yourself or you will be incompatible
9565745a
RS
115with other people's files! If you must change them for some application,
116do so in the local variables section of the time-stamped file itself.")
117
118
e1f40b28 119(defvar time-stamp-end "\\\\?[\">]" ;Do not change!
9565745a 120 "Regexp marking the text after the time stamp.
e1f40b28
RS
121\\[time-stamp] deletes the text between the first match of `time-stamp-start'
122and the following match of `time-stamp-end' on the same line,
123then writes the time stamp specified by `time-stamp-format' between them.
124
125Do not change `time-stamp-line-limit', `time-stamp-start', or
126`time-stamp-end' for yourself or you will be incompatible
127with other people's files! If you must change them for some application,
128do so in the local variables section of the time-stamped file itself.")
129
9565745a 130
03d7856a 131
59b644e8 132;;;###autoload
9565745a
RS
133(defun time-stamp ()
134 "Update the time stamp string in the buffer.
03d7856a
KH
135A template in a file can be automatically updated with a new time stamp
136every time you save the file. Add this line to your .emacs file:
137 (add-hook 'write-file-hooks 'time-stamp)
138Normally the template must appear in the first 8 lines of a file and
139look like one of the following:
140 Time-stamp: <>
141 Time-stamp: \" \"
142The time stamp is written between the brackets or quotes:
143 Time-stamp: <1996-07-18 10:20:51 gildea>
622b7ede 144The time stamp is updated only if the variable `time-stamp-active' is non-nil.
03d7856a
KH
145The format of the time stamp is set by the variable `time-stamp-format'.
146The variables `time-stamp-line-limit', `time-stamp-start',
147and `time-stamp-end' control finding the template."
9565745a 148 (interactive)
fe8287c6 149 (let ((case-fold-search nil)
03d7856a
KH
150 (start nil)
151 (end nil)
622b7ede
RS
152 search-limit
153 (line-limit time-stamp-line-limit))
154 (cond ((not (integerp line-limit))
155 (setq line-limit 8)
156 (message "time-stamp-line-limit is not a number")
157 (sit-for 1)))
158 (save-excursion
159 (save-restriction
160 (widen)
161 (cond ((> line-limit 0)
162 (goto-char (setq start (point-min)))
163 (forward-line line-limit)
164 (setq search-limit (point)))
165 (t
166 (goto-char (setq search-limit (point-max)))
167 (forward-line line-limit)
168 (setq start (point))))
169 (goto-char start)
170 (while (and (< (point) search-limit)
171 (not end)
172 (re-search-forward time-stamp-start search-limit 'move))
173 (setq start (point))
174 (end-of-line)
175 (let ((line-end (point)))
c7c4ddd4 176 (goto-char start)
622b7ede
RS
177 (if (re-search-forward time-stamp-end line-end 'move)
178 (setq end (match-beginning 0)))))))
03d7856a
KH
179 (if end
180 (progn
181 ;; do all warnings outside save-excursion
182 (cond
183 ((not time-stamp-active)
184 (if time-stamp-warn-inactive
185 ;; don't signal an error in a write-file-hook
c7c4ddd4 186 (progn
03d7856a
KH
187 (message "Warning: time-stamp-active is off; did not time-stamp buffer.")
188 (sit-for 1))))
189 ((not (and (stringp time-stamp-start)
190 (stringp time-stamp-end)))
191 (message "time-stamp-start or time-stamp-end is not a string")
192 (sit-for 1))
193 (t
194 (let ((new-time-stamp (time-stamp-string)))
195 (if (stringp new-time-stamp)
196 (save-excursion
197 (save-restriction
198 (widen)
199 (delete-region start end)
200 (goto-char start)
201 (insert new-time-stamp)
202 (setq end (point))
203 ;; remove any tabs used to format time stamp
204 (goto-char start)
205 (if (search-forward "\t" end t)
206 (untabify start end)))))))))))
9565745a
RS
207 ;; be sure to return nil so can be used on write-file-hooks
208 nil)
209
b1defad2
RS
210;;;###autoload
211(defun time-stamp-toggle-active (&optional arg)
03d7856a 212 "Toggle `time-stamp-active', setting whether \\[time-stamp] updates a buffer.
b1defad2
RS
213With arg, turn time stamping on if and only if arg is positive."
214 (interactive "P")
215 (setq time-stamp-active
216 (if (null arg)
217 (not time-stamp-active)
218 (> (prefix-numeric-value arg) 0)))
219 (message "time-stamp is now %s." (if time-stamp-active "active" "off")))
03d7856a 220
6946129c
RS
221(defconst time-stamp-no-file "(no file)"
222 "String to use when the buffer is not associated with a file.")
223
224(defun time-stamp-string-preprocess (format)
225 "Process occurrences in FORMAT of %f, %F, %h, %s and %u.
226These are replaced with the file name (nondirectory part),
227full file name, host name for mail, system name, and user name.
228Do not alter other %-combinations, and do detect %%."
622b7ede 229 (let ((result "") (pos 0) (case-fold-search nil))
6946129c
RS
230 (while (string-match "%[%uhfFs]" format pos)
231 (setq result (concat result (substring format pos (match-beginning 0))))
232 (let ((char (aref format (1+ (match-beginning 0)))))
233 (cond ((= char ?%)
234 (setq result (concat result "%%")))
235 ((= char ?u)
236 (setq result (concat result (user-login-name))))
237 ((= char ?f)
622b7ede
RS
238 (setq result (concat result
239 (if buffer-file-name
240 (file-name-nondirectory buffer-file-name)
241 time-stamp-no-file))))
242 ((= char ?F)
243 (setq result (concat result
244 (or buffer-file-name time-stamp-no-file))))
6946129c
RS
245 ((= char ?s)
246 (setq result (concat result (system-name))))
247 ((= char ?h)
248 (setq result (concat result (time-stamp-mail-host-name))))))
249 (setq pos (match-end 0)))
250 (concat result (substring format pos))))
b1defad2 251
9565745a
RS
252(defun time-stamp-string ()
253 "Generate the new string to be inserted by \\[time-stamp]."
b1defad2 254 (if (stringp time-stamp-format)
622b7ede 255 (format-time-string (time-stamp-string-preprocess time-stamp-format))
03d7856a
KH
256 ;; handle version 1 compatibility
257 (cond ((or (eq time-stamp-old-format-warn 'error)
258 (and (eq time-stamp-old-format-warn 'ask)
259 (not (y-or-n-p "Use non-string time-stamp-format? "))))
260 (message "Warning: no time-stamp: time-stamp-format not a string")
261 (sit-for 1)
262 nil)
263 (t
264 (cond ((eq time-stamp-old-format-warn 'warn)
265 (message "Obsolescent time-stamp-format type; should be string")
266 (sit-for 1)))
267 (time-stamp-fconcat time-stamp-format " ")))))
b1defad2 268
c7c4ddd4
KH
269(defconst time-stamp-no-file "(no file)"
270 "String to use when the buffer is not associated with a file.")
271
b1defad2
RS
272(defun time-stamp-mail-host-name ()
273 "Return the name of the host where the user receives mail.
274This is the value of `mail-host-address' if bound and a string,
e654f4b0 275otherwise the value of the function system-name."
b1defad2
RS
276 (or (and (boundp 'mail-host-address)
277 (stringp mail-host-address)
278 mail-host-address)
b1defad2
RS
279 (system-name)))
280
281;;; the rest of this file is for version 1 compatibility
9565745a
RS
282
283(defun time-stamp-fconcat (list sep)
e1f40b28 284 "Similar to (mapconcat 'funcall LIST SEP) but LIST allows literals.
9565745a
RS
285If an element of LIST is a symbol, it is funcalled to get the string to use;
286the separator SEP is used between two strings obtained by funcalling a
287symbol. Otherwise the element itself is inserted; no separator is used
288around literals."
289 (let ((return-string "")
290 (insert-sep-p nil))
291 (while list
292 (cond ((symbolp (car list))
293 (if insert-sep-p
294 (setq return-string (concat return-string sep)))
295 (setq return-string (concat return-string (funcall (car list))))
296 (setq insert-sep-p t))
297 (t
298 (setq return-string (concat return-string (car list)))
299 (setq insert-sep-p nil)))
300 (setq list (cdr list)))
301 return-string))
302
03d7856a 303;;; Some functions used in time-stamp-format
9565745a
RS
304
305;;; Could generate most of a message-id with
e1f40b28 306;;; '(time-stamp-yymmdd "" time-stamp-hhmm "@" time-stamp-mail-host-name)
9565745a 307
9565745a
RS
308;;; pretty form, suitable for a title page
309
310(defun time-stamp-month-dd-yyyy ()
e1f40b28 311 "Return the current date as a string in \"Month DD, YYYY\" form."
b8944601 312 (format-time-string "%B %e, %Y"))
9565745a 313
b24173f7
RS
314(defun time-stamp-dd/mm/yyyy ()
315 "Return the current date as a string in \"DD/MM/YYYY\" form."
b8944601 316 (format-time-string "%d/%m/%Y"))
b24173f7 317
9565745a
RS
318;;; same as __DATE__ in ANSI C
319
320(defun time-stamp-mon-dd-yyyy ()
e1f40b28
RS
321 "Return the current date as a string in \"Mon DD YYYY\" form.
322The first character of DD is space if the value is less than 10."
b8944601 323 (format-time-string "%b %d %Y"))
9565745a
RS
324
325;;; RFC 822 date
326
327(defun time-stamp-dd-mon-yy ()
e1f40b28 328 "Return the current date as a string in \"DD Mon YY\" form."
b8944601 329 (format-time-string "%d %b %y"))
9565745a
RS
330
331;;; RCS 3 date
332
333(defun time-stamp-yy/mm/dd ()
e1f40b28 334 "Return the current date as a string in \"YY/MM/DD\" form."
b8944601 335 (format-time-string "%y/%m/%d"))
9565745a
RS
336
337;;; RCS 5 date
338
339(defun time-stamp-yyyy/mm/dd ()
e1f40b28 340 "Return the current date as a string in \"YYYY/MM/DD\" form."
b8944601 341 (format-time-string "%Y/%m/%d"))
9565745a 342
e1f40b28 343;;; ISO 8601 date
9565745a 344
e1f40b28
RS
345(defun time-stamp-yyyy-mm-dd ()
346 "Return the current date as a string in \"YYYY-MM-DD\" form."
b8944601 347 (format-time-string "%Y-%m-%d"))
9565745a 348
e1f40b28
RS
349(defun time-stamp-yymmdd ()
350 "Return the current date as a string in \"YYMMDD\" form."
b8944601 351 (format-time-string "%y%m%d"))
9565745a
RS
352
353(defun time-stamp-hh:mm:ss ()
e1f40b28 354 "Return the current time as a string in \"HH:MM:SS\" form."
b8944601 355 (format-time-string "%T"))
9565745a 356
9565745a 357(defun time-stamp-hhmm ()
e1f40b28 358 "Return the current time as a string in \"HHMM\" form."
b8944601 359 (format-time-string "%H%M"))
9565745a
RS
360
361(provide 'time-stamp)
362
363;;; time-stamp.el ends here