changeset 18170:7776ee6215de

(time-stamp-format): Doc fix. Use %;y. (time-stamp-string-preprocess): Don't just call format-time-string; handle compatibility for some old constructs. Handle padding the historical way, while giving a warning if people actually depend on it. (time-stamp-conv-warn, time-stamp-conversion-warn) (time-stamp-do-number): New functions.
author Richard M. Stallman <rms@gnu.org>
date Sun, 08 Jun 1997 21:43:08 +0000
parents c18511c53797
children 566b6cf773ed
files lisp/time-stamp.el
diffstat 1 files changed, 248 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/time-stamp.el	Sun Jun 08 21:13:21 1997 +0000
+++ b/lisp/time-stamp.el	Sun Jun 08 21:43:08 1997 +0000
@@ -1,8 +1,8 @@
 ;;; time-stamp.el --- Maintain last change time stamps in files edited by Emacs
 
-;; Copyright 1989, 1993, 1994, 1995 Free Software Foundation, Inc.
+;; Copyright 1989, 1993, 1994, 1995, 1997 Free Software Foundation, Inc.
 
-;; Maintainer's Time-stamp: <1997-04-28 11:51:22 gildea>
+;; Maintainer's Time-stamp: <1997-06-01 17:02:45 gildea>
 ;; Maintainer: Stephen Gildea <gildea@alum.mit.edu>
 ;; Keywords: tools
 
@@ -66,23 +66,47 @@
                  (const ask) (const warn))
   :group 'time-stamp)
 
-(defcustom time-stamp-format "%Y-%02m-%02d %02H:%02M:%02S %u"
+(defcustom time-stamp-format "%:y-%02m-%02d %02H:%02M:%02S %u"
   "*Format of the string inserted by \\[time-stamp].
 The value may be a string or a list.  Lists are supported only for
 backward compatibility; see variable `time-stamp-old-format-warn'.
 
-A string is used with `format-time-string'.
-In addition to the features of `format-time-string',
-you can use the following %-constructs:
+A string is used verbatim except for character sequences beginning with %:
 
-%f  file name without directory
-%F  full file name
-%h  mail host name
-%s  system name
-%u  user's login name
+%:a  weekday name: `Monday'.		%#A gives uppercase: `MONDAY'
+%3a  abbreviated weekday: `Mon'.	%3A gives uppercase: `MON'
+%:b  month name: `January'.		%#B gives uppercase: `JANUARY'
+%3b  abbreviated month: `Jan'.		%3B gives uppercase: `JAN'
+%02d day of month
+%02H 24-hour clock hour
+%02I 12-hour clock hour
+%02m month number
+%02M minute
+%#p  `am' or `pm'.			%P  gives uppercase: `AM' or `PM'
+%02S seconds
+%w   day number of week, Sunday is 0
+%02y 2-digit year: `97'			%:y 4-digit year: `1997'
+%z   time zone name: `est'.		%Z  gives uppercase: `EST'
+
+Non-date items:
+%%   a literal percent character: `%'
+%f   file name without directory	%F  gives absolute pathname
+%s   system name
+%u   user's login name
+%h   mail host name
+
+Decimal digits between the % and the type character specify the
+field width.  Strings are truncated on the right; years on the left.
+A leading zero causes numbers to be zero-filled.
 
 For example, to get the format used by the `date' command,
-use \"%3a %3b %2d %02H:%02M:%02S %Z %Y\"."
+use \"%3a %3b %2d %02H:%02M:%02S %Z %:y\".
+
+In the future these formats will be aligned more with format-time-string.
+Because of this transition, the default padding for numeric formats will
+change in a future version.  Therefore either a padding width should be
+specified, or the : modifier should be used to explicitly request the
+historical default."
   :type 'string
   :group 'time-stamp)
 
@@ -221,33 +245,218 @@
 (defconst time-stamp-no-file "(no file)"
   "String to use when the buffer is not associated with a file.")
 
-(defun time-stamp-string-preprocess (format)
-  "Process occurrences in FORMAT of %f, %F, %h, %s and %u.
-These are replaced with the file name (nondirectory part),
-full file name, host name for mail, system name, and user name.
-Do not alter other %-combinations, and do detect %%."
-  (let ((result "") (pos 0) (case-fold-search nil))
-    (while (string-match "%[%uhfFs]" format pos)
-      (setq result (concat result (substring format pos (match-beginning 0))))
-      (let ((char (aref format (1+ (match-beginning 0)))))
-	(cond ((= char ?%)
-	       (setq result (concat result "%%")))
-	      ((= char ?u)
-	       (setq result (concat result (user-login-name))))
-	      ((= char ?f)
-	       (setq result (concat result
-				    (if buffer-file-name
-					(file-name-nondirectory buffer-file-name)
-				      time-stamp-no-file))))
-	      ((= char ?F)
-	       (setq result (concat result
-				    (or buffer-file-name time-stamp-no-file))))
-	      ((= char ?s)
-	       (setq result (concat result (system-name))))
-	      ((= char ?h)
-	       (setq result (concat result (time-stamp-mail-host-name))))))
-      (setq pos (match-end 0)))
-    (concat result (substring format pos))))
+;;; time-stamp is transitioning to using the new, expanded capabilities
+;;; of format-time-string.  During the process, this function implements
+;;; intermediate, compatible formats and complains about old, soon to
+;;; be unsupported, formats.  This function will get a lot (a LOT) shorter
+;;; when the transition is complete and we can just pass most things
+;;; straight through to format-time-string.
+;;;      At all times, all the formats recommended in the doc string
+;;; of time-stamp-format will work not only in the current version of
+;;; Emacs, but in all versions that have been released within the past
+;;; two years.
+;;;      The : modifier is a temporary conversion feature used to resolve
+;;; ambiguous formats--formats that are changing (over time) incompatibly.
+(defun time-stamp-string-preprocess (format &optional time)
+  ;; Uses a FORMAT to format date, time, file, and user information.
+  ;; Optional second argument TIME is only for testing.
+  ;; Implements non-time extensions to format-time-string
+  ;; and all time-stamp-format compatibility.
+  (let ((fmt-len (length format))
+	(ind 0)
+	cur-char
+	(prev-char nil)
+	(result "")
+	field-index
+	field-width
+	field-result
+	alt-form change-case require-padding
+	(paren-level 0))
+    (while (< ind fmt-len)
+      (setq cur-char (aref format ind))
+      (setq
+       result
+       (concat result
+      (cond
+       ((eq cur-char ?%)
+	;; eat any additional args to allow for future expansion
+	(setq alt-form nil change-case nil require-padding nil)
+	(while (progn
+		 (setq ind (1+ ind))
+		 (setq cur-char (if (< ind fmt-len)
+				    (aref format ind)
+				  ?\0))
+		 (or (eq ?. cur-char)
+		     (eq ?, cur-char) (eq ?: cur-char) (eq ?@ cur-char)
+		     (eq ?- cur-char) (eq ?+ cur-char) (eq ?_ cur-char) 
+		     (eq ?\  cur-char) (eq ?# cur-char) (eq ?^ cur-char)
+		     (and (eq ?\( cur-char)
+			  (not (eq prev-char ?\\))
+			  (setq paren-level (1+ paren-level)))
+		     (if (and (eq ?\) cur-char)
+			      (not (eq prev-char ?\\))
+			      (> paren-level 0))
+			 (setq paren-level (1- paren-level))
+		       (and (> paren-level 0)
+			    (< ind fmt-len)))))
+	  (setq prev-char cur-char)
+	  ;; some characters we actually use
+	  (cond ((eq cur-char ?:)
+		 (setq alt-form t))
+		((eq cur-char ?#)
+		 (setq change-case t))))
+	;; get format width
+	(setq field-index ind)
+	(setq ind (1- ind))
+	(while (progn
+		 (setq ind (1+ ind))
+		 (setq cur-char (if (< ind fmt-len)
+				    (aref format ind)
+				  ?\0))
+		 (and (<= ?0 cur-char) (>= ?9 cur-char))))
+	(setq field-width (substring format field-index ind))
+	(setq field-result
+	(cond
+	 ((eq cur-char ?%)
+	  "%")
+	 ((eq cur-char ?a)		;day of week
+	  (if change-case
+	      (format-time-string "%#A" time)
+	    (or alt-form (not (string-equal field-width ""))
+		(time-stamp-conv-warn "%a" "%:a"))
+	    (if (and alt-form (not (string-equal field-width "")))
+		""			;discourage "%:3a"
+	      (format-time-string "%A" time))))
+	 ((eq cur-char ?A)
+	  (if alt-form
+	      (format-time-string "%A" time)
+	    (or change-case (not (string-equal field-width ""))
+		(time-stamp-conv-warn "%A" "%#A"))
+	    (format-time-string "%#A" time)))
+	 ((eq cur-char ?b)		;month name
+	  (if change-case
+	      (format-time-string "%#B" time)
+	    (or alt-form (not (string-equal field-width ""))
+		(time-stamp-conv-warn "%b" "%:b"))
+	    (if (and alt-form (not (string-equal field-width "")))
+		""			;discourage "%:3b"
+	    (format-time-string "%B" time))))
+	 ((eq cur-char ?B)
+	  (if alt-form
+	      (format-time-string "%B" time)
+	    (or change-case (not (string-equal field-width ""))
+		(time-stamp-conv-warn "%B" "%#B"))
+	    (format-time-string "%#B" time)))
+	 ((eq cur-char ?d)		;day of month, 1-31
+	  (time-stamp-do-number cur-char))
+	 ((eq cur-char ?H)		;hour, 0-23
+	  (time-stamp-do-number cur-char))
+	 ((eq cur-char ?I)		;hour, 1-12
+	  (time-stamp-do-number cur-char))
+	 ((eq cur-char ?m)		;month number, 1-12
+	  (time-stamp-do-number cur-char))
+	 ((eq cur-char ?M)		;minute, 0-59
+	  (time-stamp-do-number cur-char))
+	 ((eq cur-char ?p)		;am or pm
+	  (or change-case
+	      (time-stamp-conv-warn "%p" "%#p"))
+	  (format-time-string "%#p" time))
+	 ((eq cur-char ?P)		;AM or PM
+	  (format-time-string "%p" time))
+	 ((eq cur-char ?S)		;seconds, 00-60
+	  (time-stamp-do-number cur-char))
+	 ((eq cur-char ?w)		;weekday number, Sunday is 0
+	  (format-time-string "%w" time))
+	 ((eq cur-char ?y)		;year
+	  (or alt-form (not (string-equal field-width ""))
+	      (time-stamp-conv-warn "%y" "%:y"))
+	  (string-to-int (format-time-string "%Y" time)))
+	 ((eq cur-char ?Y)		;4-digit year, new style
+	  (string-to-int (format-time-string "%Y" time)))
+	 ((eq cur-char ?z)		;time zone lower case
+	  (if change-case
+	      ""			;discourage %z variations
+	    (format-time-string "%#Z" time)))
+	 ((eq cur-char ?Z)
+	  (if change-case
+	      (format-time-string "%#Z" time)
+	    (format-time-string "%Z" time)))
+	 ((eq cur-char ?f)		;buffer-file-name, base name only
+	  (if buffer-file-name
+	      (file-name-nondirectory buffer-file-name)
+	    time-stamp-no-file))
+	 ((eq cur-char ?F)		;buffer-file-name, full path
+	  (or buffer-file-name
+	      time-stamp-no-file))
+	 ((eq cur-char ?s)		;system name
+	  (system-name))
+	 ((eq cur-char ?u)		;user name
+	  (user-login-name))
+	 ((eq cur-char ?h)		;mail host name
+	  (time-stamp-mail-host-name))
+	 ))
+	(if (string-equal field-width "")
+	    field-result
+	  (let ((padded-result
+		 (format (format "%%%s%c"
+				 field-width
+				 (if (numberp field-result) ?d ?s))
+			 (or field-result ""))))
+	    (let ((initial-length (length padded-result))
+		  (desired-length (string-to-int field-width)))
+	      (if (> initial-length desired-length)
+		  ;; truncate strings on right, years on left
+		  (if (stringp field-result)
+		      (substring padded-result 0 desired-length)
+		    (if (eq cur-char ?y)
+			(substring padded-result (- desired-length))
+		      padded-result))	;non-year numbers don't truncate
+		padded-result)))))
+       (t
+	(char-to-string cur-char)))))
+      (setq ind (1+ ind)))
+    result))
+
+(defun time-stamp-do-number (format-char)
+  ;; Handle compatible cases where only
+  ;; the default width/padding will change.
+  ;; Uses dynamic vars field-width, time.
+  (let ((format-string (concat "%" (char-to-string format-char))))
+    (and (not alt-form) (string-equal field-width "")
+	 (time-stamp-conv-warn format-string
+			       (format "%%:%c" format-char)))
+    (if (and alt-form (not (string-equal field-width "")))
+	""				;discourage "%:2d" and the like
+      (string-to-int (format-time-string format-string time)))))
+
+(defvar time-stamp-conversion-warn t
+  "Non-nil to warn about soon-to-be-unsupported forms in time-stamp-format.
+In would be a bad idea to disable these warnings!
+You really need to update your files instead.
+
+The new formats will work with old versions of Emacs.
+New formats are being recommended now to allow time-stamp-format
+to change in the future to be compatible with format-time-string.
+The new forms being recommended now will continue to work then.")
+
+
+(defun time-stamp-conv-warn (old-form new-form)
+  ;; Display a warning about a soon-to-be-obsolete format.
+  (cond
+   (time-stamp-conversion-warn
+    (save-excursion
+      (set-buffer (get-buffer-create "*Time-stamp-compatibility*"))
+      (goto-char (point-max))
+      (if (bobp)
+	  (progn
+	    (insert
+	     "The formats recognized in time-stamp-format will change in a future release\n"
+	     "to be compatible with the new, expanded format-time-string function.\n\n"
+	     "The following obsolescent time-stamp-format construct(s) were found:\n\n")))
+      (insert "\"" old-form "\" -- use " new-form "\n"))
+    (display-buffer "*Time-stamp-compatibility*"))))
+  
+
 
 (defun time-stamp-string ()
   "Generate the new string to be inserted by \\[time-stamp]."