(MKTIME_OBJ):
[emacs.git] / lisp / time-stamp.el
blob85351d741f837f7ca433f700227fe69c88d1c5b1
1 ;;; time-stamp.el --- Maintain last change time stamps in files edited by Emacs
3 ;; Copyright 1989, 1993, 1994, 1995 Free Software Foundation, Inc.
5 ;; Maintainer's Time-stamp: <1996-08-13 14:03:17 gildea>
6 ;; Maintainer: Stephen Gildea <gildea@lcs.mit.edu>
7 ;; Keywords: tools
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.
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.
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.
24 ;;; Commentary:
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.
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.
35 ;; See the documentation for the functions `time-stamp'
36 ;; and `time-stamp-toggle-active' for details.
38 ;;; Change Log:
40 ;; Originally based on the 19 Dec 88 version of
41 ;; date.el by John Sturdy <mcvax!harlqn.co.uk!jcgs@uunet.uu.net>
42 ;; Version 2, January 1995: replaced functions with %-escapes
43 ;; $Id: time-stamp.el,v 1.23 1996/12/17 00:19:01 rms Exp rms $
45 ;;; Code:
47 (defvar time-stamp-active t
48 "*Non-nil to enable time-stamping of buffers by \\[time-stamp].
49 Can be toggled by \\[time-stamp-toggle-active].
50 See also the variable `time-stamp-warn-inactive'.")
52 (defvar 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.")
57 (defvar time-stamp-old-format-warn 'ask
58 "Action to take if `time-stamp-format' is an old-style list.
59 If `error', the format is not used. If `ask', the user is queried about
60 using the time-stamp-format. If `warn', a warning is displayed.
61 If nil, no notification is given.")
63 (defvar time-stamp-format "%Y-%m-%d %H:%M:%S %u"
64 "*Format of the string inserted by \\[time-stamp].
65 The value may be a string or a list. Lists are supported only for
66 backward compatibility; see variable `time-stamp-old-format-warn'.
68 A string is used with `format-time-string'.
69 For example, to get the format used by the `date' command,
70 use \"%3a %3b %2d %H:%M:%S %Z %y\".
72 In addition to the features of `format-time-string',
73 you can use the following %-constructs:
75 %f file name without directory
76 %F full file name
77 %h mail host name
78 %s system name
79 %u user's login name")
81 ;;; Do not change time-stamp-line-limit, time-stamp-start, or
82 ;;; time-stamp-end in your .emacs or you will be incompatible
83 ;;; with other people's files! If you must change them,
84 ;;; do so only in the local variables section of the file itself.
87 (defvar time-stamp-line-limit 8 ;Do not change!
88 "Lines of a file searched; positive counts from start, negative from end.
89 The patterns `time-stamp-start' and `time-stamp-end' must be found on one
90 of the first (last) `time-stamp-line-limit' lines of the file for the
91 file to be time-stamped by \\[time-stamp].
93 Do not change `time-stamp-line-limit', `time-stamp-start', or
94 `time-stamp-end' for yourself or you will be incompatible
95 with other people's files! If you must change them for some application,
96 do so in the local variables section of the time-stamped file itself.")
99 (defvar time-stamp-start "Time-stamp:[ \t]+\\\\?[\"<]+" ;Do not change!
100 "Regexp after which the time stamp is written by \\[time-stamp].
101 See also the variables `time-stamp-end' and `time-stamp-line-limit'.
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.")
109 (defvar time-stamp-end "\\\\?[\">]" ;Do not change!
110 "Regexp marking the text after the time stamp.
111 \\[time-stamp] deletes the text between the first match of `time-stamp-start'
112 and the following match of `time-stamp-end' on the same line,
113 then writes the time stamp specified by `time-stamp-format' between them.
115 Do not change `time-stamp-line-limit', `time-stamp-start', or
116 `time-stamp-end' for yourself or you will be incompatible
117 with other people's files! If you must change them for some application,
118 do so in the local variables section of the time-stamped file itself.")
122 ;;;###autoload
123 (defun time-stamp ()
124 "Update the time stamp string in the buffer.
125 A template in a file can be automatically updated with a new time stamp
126 every time you save the file. Add this line to your .emacs file:
127 (add-hook 'write-file-hooks 'time-stamp)
128 Normally the template must appear in the first 8 lines of a file and
129 look like one of the following:
130 Time-stamp: <>
131 Time-stamp: \" \"
132 The time stamp is written between the brackets or quotes:
133 Time-stamp: <1996-07-18 10:20:51 gildea>
134 Only updates the time stamp if the variable `time-stamp-active' is non-nil.
135 The format of the time stamp is set by the variable `time-stamp-format'.
136 The variables `time-stamp-line-limit', `time-stamp-start',
137 and `time-stamp-end' control finding the template."
138 (interactive)
139 (let ((case-fold-search nil)
140 (start nil)
141 (end nil)
142 search-limit)
143 (save-excursion
144 (save-restriction
145 (widen)
146 (cond ((> time-stamp-line-limit 0)
147 (goto-char (setq start (point-min)))
148 (forward-line time-stamp-line-limit)
149 (setq search-limit (point)))
151 (goto-char (setq search-limit (point-max)))
152 (forward-line time-stamp-line-limit)
153 (setq start (point))))
154 (goto-char start)
155 (while (and (< (point) search-limit)
156 (not end)
157 (re-search-forward time-stamp-start search-limit 'move))
158 (setq start (point))
159 (end-of-line)
160 (let ((line-end (point)))
161 (goto-char start)
162 (if (re-search-forward time-stamp-end line-end 'move)
163 (setq end (match-beginning 0)))))))
164 (if end
165 (progn
166 ;; do all warnings outside save-excursion
167 (cond
168 ((not time-stamp-active)
169 (if time-stamp-warn-inactive
170 ;; don't signal an error in a write-file-hook
171 (progn
172 (message "Warning: time-stamp-active is off; did not time-stamp buffer.")
173 (sit-for 1))))
174 ((not (and (stringp time-stamp-start)
175 (stringp time-stamp-end)))
176 (message "time-stamp-start or time-stamp-end is not a string")
177 (sit-for 1))
179 (let ((new-time-stamp (time-stamp-string)))
180 (if (stringp new-time-stamp)
181 (save-excursion
182 (save-restriction
183 (widen)
184 (delete-region start end)
185 (goto-char start)
186 (insert new-time-stamp)
187 (setq end (point))
188 ;; remove any tabs used to format time stamp
189 (goto-char start)
190 (if (search-forward "\t" end t)
191 (untabify start end)))))))))))
192 ;; be sure to return nil so can be used on write-file-hooks
193 nil)
195 ;;;###autoload
196 (defun time-stamp-toggle-active (&optional arg)
197 "Toggle `time-stamp-active', setting whether \\[time-stamp] updates a buffer.
198 With arg, turn time stamping on if and only if arg is positive."
199 (interactive "P")
200 (setq time-stamp-active
201 (if (null arg)
202 (not time-stamp-active)
203 (> (prefix-numeric-value arg) 0)))
204 (message "time-stamp is now %s." (if time-stamp-active "active" "off")))
206 (defconst time-stamp-no-file "(no file)"
207 "String to use when the buffer is not associated with a file.")
209 (defun time-stamp-string-preprocess (format)
210 "Process occurrences in FORMAT of %f, %F, %h, %s and %u.
211 These are replaced with the file name (nondirectory part),
212 full file name, host name for mail, system name, and user name.
213 Do not alter other %-combinations, and do detect %%."
214 (let ((result "") (pos 0) (case-fold-search nil)
215 (file (or buffer-file-name "(no file)")))
216 (while (string-match "%[%uhfFs]" format pos)
217 (setq result (concat result (substring format pos (match-beginning 0))))
218 (let ((char (aref format (1+ (match-beginning 0)))))
219 (cond ((= char ?%)
220 (setq result (concat result "%%")))
221 ((= char ?u)
222 (setq result (concat result (user-login-name))))
223 ((= char ?f)
224 (setq result (concat result (file-name-nondirectory file))))
225 ((= char ?f)
226 (setq result (concat result file)))
227 ((= char ?s)
228 (setq result (concat result (system-name))))
229 ((= char ?h)
230 (setq result (concat result (time-stamp-mail-host-name))))))
231 (setq pos (match-end 0)))
232 (concat result (substring format pos))))
234 (defun time-stamp-string ()
235 "Generate the new string to be inserted by \\[time-stamp]."
236 (if (stringp time-stamp-format)
237 (format-time-string (time-stamp-string-preprocess time-stamp-format)
238 (current-time))
239 ;; handle version 1 compatibility
240 (cond ((or (eq time-stamp-old-format-warn 'error)
241 (and (eq time-stamp-old-format-warn 'ask)
242 (not (y-or-n-p "Use non-string time-stamp-format? "))))
243 (message "Warning: no time-stamp: time-stamp-format not a string")
244 (sit-for 1)
245 nil)
247 (cond ((eq time-stamp-old-format-warn 'warn)
248 (message "Obsolescent time-stamp-format type; should be string")
249 (sit-for 1)))
250 (time-stamp-fconcat time-stamp-format " ")))))
252 (defconst time-stamp-no-file "(no file)"
253 "String to use when the buffer is not associated with a file.")
255 (defun time-stamp-mail-host-name ()
256 "Return the name of the host where the user receives mail.
257 This is the value of `mail-host-address' if bound and a string,
258 otherwise the value of the function system-name."
259 (or (and (boundp 'mail-host-address)
260 (stringp mail-host-address)
261 mail-host-address)
262 (system-name)))
264 ;;; the rest of this file is for version 1 compatibility
266 (defun time-stamp-fconcat (list sep)
267 "Similar to (mapconcat 'funcall LIST SEP) but LIST allows literals.
268 If an element of LIST is a symbol, it is funcalled to get the string to use;
269 the separator SEP is used between two strings obtained by funcalling a
270 symbol. Otherwise the element itself is inserted; no separator is used
271 around literals."
272 (let ((return-string "")
273 (insert-sep-p nil))
274 (while list
275 (cond ((symbolp (car list))
276 (if insert-sep-p
277 (setq return-string (concat return-string sep)))
278 (setq return-string (concat return-string (funcall (car list))))
279 (setq insert-sep-p t))
281 (setq return-string (concat return-string (car list)))
282 (setq insert-sep-p nil)))
283 (setq list (cdr list)))
284 return-string))
286 ;;; Some functions used in time-stamp-format
288 ;;; Could generate most of a message-id with
289 ;;; '(time-stamp-yymmdd "" time-stamp-hhmm "@" time-stamp-mail-host-name)
291 ;;; pretty form, suitable for a title page
293 (defun time-stamp-month-dd-yyyy ()
294 "Return the current date as a string in \"Month DD, YYYY\" form."
295 (format-time-string "%B %e, %Y"))
297 (defun time-stamp-dd/mm/yyyy ()
298 "Return the current date as a string in \"DD/MM/YYYY\" form."
299 (format-time-string "%d/%m/%Y"))
301 ;;; same as __DATE__ in ANSI C
303 (defun time-stamp-mon-dd-yyyy ()
304 "Return the current date as a string in \"Mon DD YYYY\" form.
305 The first character of DD is space if the value is less than 10."
306 (format-time-string "%b %d %Y"))
308 ;;; RFC 822 date
310 (defun time-stamp-dd-mon-yy ()
311 "Return the current date as a string in \"DD Mon YY\" form."
312 (format-time-string "%d %b %y"))
314 ;;; RCS 3 date
316 (defun time-stamp-yy/mm/dd ()
317 "Return the current date as a string in \"YY/MM/DD\" form."
318 (format-time-string "%y/%m/%d"))
320 ;;; RCS 5 date
322 (defun time-stamp-yyyy/mm/dd ()
323 "Return the current date as a string in \"YYYY/MM/DD\" form."
324 (format-time-string "%Y/%m/%d"))
326 ;;; ISO 8601 date
328 (defun time-stamp-yyyy-mm-dd ()
329 "Return the current date as a string in \"YYYY-MM-DD\" form."
330 (format-time-string "%Y-%m-%d"))
332 (defun time-stamp-yymmdd ()
333 "Return the current date as a string in \"YYMMDD\" form."
334 (format-time-string "%y%m%d"))
336 (defun time-stamp-hh:mm:ss ()
337 "Return the current time as a string in \"HH:MM:SS\" form."
338 (format-time-string "%T"))
340 (defun time-stamp-hhmm ()
341 "Return the current time as a string in \"HHMM\" form."
342 (format-time-string "%H%M"))
344 (provide 'time-stamp)
346 ;;; time-stamp.el ends here