]> code.delx.au - gnu-emacs/blob - lisp/time-stamp.el
Comment change.
[gnu-emacs] / lisp / time-stamp.el
1 ;;; time-stamp.el --- Maintain last change time stamps in files edited by Emacs
2
3 ;; Copyright 1989, 1993, 1994, 1995 Free Software Foundation, Inc.
4
5 ;; Maintainer's Time-stamp: <1997-04-28 11:51:22 gildea>
6 ;; Maintainer: Stephen Gildea <gildea@alum.mit.edu>
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
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.
23
24 ;;; Commentary:
25
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.
37
38 ;;; Code:
39
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
46 "*Non-nil to enable time-stamping of buffers by \\[time-stamp].
47 Can be toggled by \\[time-stamp-toggle-active].
48 See also the variable `time-stamp-warn-inactive'."
49 :type 'boolean
50 :group 'time-stamp)
51
52 (defcustom time-stamp-warn-inactive t
53 "Non-nil to have \\[time-stamp] warn if a buffer did not get time-stamped.
54 A warning is printed if `time-stamp-active' is nil and the buffer contains
55 a time stamp template that would otherwise have been updated."
56 :type 'boolean
57 :group 'time-stamp)
58
59 (defcustom time-stamp-old-format-warn 'ask
60 "Action to take if `time-stamp-format' is an old-style list.
61 If `error', the format is not used. If `ask', the user is queried about
62 using the time-stamp-format. If `warn', a warning is displayed.
63 If nil, no notification is given."
64 :type '(choice (const :tag "No notification" nil)
65 (const :tag "Don't use the format" error)
66 (const ask) (const warn))
67 :group 'time-stamp)
68
69 (defcustom time-stamp-format "%Y-%02m-%02d %02H:%02M:%02S %u"
70 "*Format of the string inserted by \\[time-stamp].
71 The value may be a string or a list. Lists are supported only for
72 backward compatibility; see variable `time-stamp-old-format-warn'.
73
74 A string is used with `format-time-string'.
75 In addition to the features of `format-time-string',
76 you 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
82 %u user's login name
83
84 For example, to get the format used by the `date' command,
85 use \"%3a %3b %2d %02H:%02M:%02S %Z %Y\"."
86 :type 'string
87 :group 'time-stamp)
88
89
90
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
96
97 (defvar time-stamp-line-limit 8 ;Do not change!
98 "Lines of a file searched; positive counts from start, negative from end.
99 The patterns `time-stamp-start' and `time-stamp-end' must be found on one
100 of the first (last) `time-stamp-line-limit' lines of the file for the
101 file to be time-stamped by \\[time-stamp].
102
103 Do not change `time-stamp-line-limit', `time-stamp-start', or
104 `time-stamp-end' for yourself or you will be incompatible
105 with other people's files! If you must change them for some application,
106 do so in the local variables section of the time-stamped file itself.")
107
108
109 (defvar time-stamp-start "Time-stamp:[ \t]+\\\\?[\"<]+" ;Do not change!
110 "Regexp after which the time stamp is written by \\[time-stamp].
111 See also the variables `time-stamp-end' and `time-stamp-line-limit'.
112
113 Do not change `time-stamp-line-limit', `time-stamp-start', or
114 `time-stamp-end' for yourself or you will be incompatible
115 with other people's files! If you must change them for some application,
116 do so in the local variables section of the time-stamped file itself.")
117
118
119 (defvar time-stamp-end "\\\\?[\">]" ;Do not change!
120 "Regexp marking the text after the time stamp.
121 \\[time-stamp] deletes the text between the first match of `time-stamp-start'
122 and the following match of `time-stamp-end' on the same line,
123 then writes the time stamp specified by `time-stamp-format' between them.
124
125 Do not change `time-stamp-line-limit', `time-stamp-start', or
126 `time-stamp-end' for yourself or you will be incompatible
127 with other people's files! If you must change them for some application,
128 do so in the local variables section of the time-stamped file itself.")
129
130
131
132 ;;;###autoload
133 (defun time-stamp ()
134 "Update the time stamp string in the buffer.
135 A template in a file can be automatically updated with a new time stamp
136 every time you save the file. Add this line to your .emacs file:
137 (add-hook 'write-file-hooks 'time-stamp)
138 Normally the template must appear in the first 8 lines of a file and
139 look like one of the following:
140 Time-stamp: <>
141 Time-stamp: \" \"
142 The time stamp is written between the brackets or quotes:
143 Time-stamp: <1996-07-18 10:20:51 gildea>
144 The time stamp is updated only if the variable `time-stamp-active' is non-nil.
145 The format of the time stamp is set by the variable `time-stamp-format'.
146 The variables `time-stamp-line-limit', `time-stamp-start',
147 and `time-stamp-end' control finding the template."
148 (interactive)
149 (let ((case-fold-search nil)
150 (start nil)
151 (end nil)
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)))
176 (goto-char start)
177 (if (re-search-forward time-stamp-end line-end 'move)
178 (setq end (match-beginning 0)))))))
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
186 (progn
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)))))))))))
207 ;; be sure to return nil so can be used on write-file-hooks
208 nil)
209
210 ;;;###autoload
211 (defun time-stamp-toggle-active (&optional arg)
212 "Toggle `time-stamp-active', setting whether \\[time-stamp] updates a buffer.
213 With 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")))
220
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.
226 These are replaced with the file name (nondirectory part),
227 full file name, host name for mail, system name, and user name.
228 Do not alter other %-combinations, and do detect %%."
229 (let ((result "") (pos 0) (case-fold-search nil))
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)
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))))
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))))
251
252 (defun time-stamp-string ()
253 "Generate the new string to be inserted by \\[time-stamp]."
254 (if (stringp time-stamp-format)
255 (format-time-string (time-stamp-string-preprocess time-stamp-format))
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 " ")))))
268
269 (defconst time-stamp-no-file "(no file)"
270 "String to use when the buffer is not associated with a file.")
271
272 (defun time-stamp-mail-host-name ()
273 "Return the name of the host where the user receives mail.
274 This is the value of `mail-host-address' if bound and a string,
275 otherwise the value of the function system-name."
276 (or (and (boundp 'mail-host-address)
277 (stringp mail-host-address)
278 mail-host-address)
279 (system-name)))
280
281 ;;; the rest of this file is for version 1 compatibility
282
283 (defun time-stamp-fconcat (list sep)
284 "Similar to (mapconcat 'funcall LIST SEP) but LIST allows literals.
285 If an element of LIST is a symbol, it is funcalled to get the string to use;
286 the separator SEP is used between two strings obtained by funcalling a
287 symbol. Otherwise the element itself is inserted; no separator is used
288 around 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
303 ;;; Some functions used in time-stamp-format
304
305 ;;; Could generate most of a message-id with
306 ;;; '(time-stamp-yymmdd "" time-stamp-hhmm "@" time-stamp-mail-host-name)
307
308 ;;; pretty form, suitable for a title page
309
310 (defun time-stamp-month-dd-yyyy ()
311 "Return the current date as a string in \"Month DD, YYYY\" form."
312 (format-time-string "%B %e, %Y"))
313
314 (defun time-stamp-dd/mm/yyyy ()
315 "Return the current date as a string in \"DD/MM/YYYY\" form."
316 (format-time-string "%d/%m/%Y"))
317
318 ;;; same as __DATE__ in ANSI C
319
320 (defun time-stamp-mon-dd-yyyy ()
321 "Return the current date as a string in \"Mon DD YYYY\" form.
322 The first character of DD is space if the value is less than 10."
323 (format-time-string "%b %d %Y"))
324
325 ;;; RFC 822 date
326
327 (defun time-stamp-dd-mon-yy ()
328 "Return the current date as a string in \"DD Mon YY\" form."
329 (format-time-string "%d %b %y"))
330
331 ;;; RCS 3 date
332
333 (defun time-stamp-yy/mm/dd ()
334 "Return the current date as a string in \"YY/MM/DD\" form."
335 (format-time-string "%y/%m/%d"))
336
337 ;;; RCS 5 date
338
339 (defun time-stamp-yyyy/mm/dd ()
340 "Return the current date as a string in \"YYYY/MM/DD\" form."
341 (format-time-string "%Y/%m/%d"))
342
343 ;;; ISO 8601 date
344
345 (defun time-stamp-yyyy-mm-dd ()
346 "Return the current date as a string in \"YYYY-MM-DD\" form."
347 (format-time-string "%Y-%m-%d"))
348
349 (defun time-stamp-yymmdd ()
350 "Return the current date as a string in \"YYMMDD\" form."
351 (format-time-string "%y%m%d"))
352
353 (defun time-stamp-hh:mm:ss ()
354 "Return the current time as a string in \"HH:MM:SS\" form."
355 (format-time-string "%T"))
356
357 (defun time-stamp-hhmm ()
358 "Return the current time as a string in \"HHMM\" form."
359 (format-time-string "%H%M"))
360
361 (provide 'time-stamp)
362
363 ;;; time-stamp.el ends here