gnus-art.el (gnus-mime-buttonize-attachments-in-header): Improve criterion that finds...
[gnus] / lisp / parse-time.el
index b0e8cac..42b4991 100644 (file)
@@ -1,7 +1,6 @@
 ;;; parse-time.el --- parsing time strings
 
-;; Copyright (C) 1996, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-;;   2008, 2009  Free Software Foundation, Inc.
+;; Copyright (C) 1996, 2000-2014 Free Software Foundation, Inc.
 
 ;; Author: Erik Naggum <erik@naggum.no>
 ;; Keywords: util
@@ -37,6 +36,9 @@
 
 (eval-when-compile (require 'cl))      ;and ah ain't kiddin' 'bout it
 
+(eval-and-compile
+  (when (featurep 'xemacs)
+    (defvar parse-time-syntax (make-vector 256 nil))))
 (defvar parse-time-digits (make-vector 256 nil))
 
 ;; Byte-compiler warnings
   (loop for i from ?0 to ?9
     do (aset parse-time-digits i (- i ?0))))
 
+(when (featurep 'xemacs)
+  (unless (aref parse-time-syntax ?0)
+    (loop for i from ?0 to ?9
+         do (aset parse-time-syntax i ?0))
+    (loop for i from ?A to ?Z
+         do (aset parse-time-syntax i ?A))
+    (loop for i from ?a to ?z
+         do (aset parse-time-syntax i ?a))
+    (aset parse-time-syntax ?+ 1)
+    (aset parse-time-syntax ?- -1)
+    (aset parse-time-syntax ?: ?d)))
+
 (defsubst digit-char-p (char)
   (aref parse-time-digits char))
 
-(defsubst parse-time-string-chars (char)
-  (save-match-data
-    (let (case-fold-search str)
-      (cond ((eq char ?+) 1)
-           ((eq char ?-) -1)
-           ((eq char ?:) ?d)
-           ((string-match "[[:upper:]]" (setq str (string char))) ?A)
-           ((string-match "[[:lower:]]" str) ?a)
-           ((string-match "[[:digit:]]" str) ?0)))))
+(eval-and-compile
+  (if (featurep 'xemacs)
+      (defsubst parse-time-string-chars (char)
+       (and (< char (length parse-time-syntax))
+            (aref parse-time-syntax char)))
+    (defsubst parse-time-string-chars (char)
+      (save-match-data
+       (let (case-fold-search str)
+         (cond ((eq char ?+) 1)
+               ((eq char ?-) -1)
+               ((eq char ?:) ?d)
+               ((string-match "[[:upper:]]" (setq str (string char))) ?A)
+               ((string-match "[[:lower:]]" str) ?a)
+               ((string-match "[[:digit:]]" str) ?0)))))))
 
 (put 'parse-error 'error-conditions '(parse-error error))
 (put 'parse-error 'error-message "Parsing error")
        (index 0)
        (c nil))
     (while (< index end)
-      (while (and (< index end)                ;skip invalid characters
+      (while (and (< index end)                ;Skip invalid characters.
                  (not (setq c (parse-time-string-chars (aref string index)))))
        (incf index))
       (setq start index all-digits (eq c ?0))
-      (while (and (< (incf index) end) ;scan valid characters
+      (while (and (< (incf index) end) ;Scan valid characters.
                  (setq c (parse-time-string-chars (aref string index))))
        (setq all-digits (and all-digits (eq c ?0))))
       (if (<= index end)
@@ -194,31 +213,93 @@ unknown are returned as nil."
                 (predicate (pop rule))
                 (parse-time-val))
            (when (and (not (nth (car slots) time)) ;not already set
-                      (setq parse-time-val (cond ((and (consp predicate)
-                                            (not (eq (car predicate)
-                                                     'lambda)))
-                                       (and (numberp parse-time-elt)
-                                            (<= (car predicate) parse-time-elt)
-                                            (<= parse-time-elt (cadr predicate))
-                                            parse-time-elt))
-                                      ((symbolp predicate)
-                                       (cdr (assoc parse-time-elt
-                                                   (symbol-value predicate))))
-                                      ((funcall predicate)))))
+                      (setq parse-time-val
+                            (cond ((and (consp predicate)
+                                        (not (eq (car predicate)
+                                                 'lambda)))
+                                   (and (numberp parse-time-elt)
+                                        (<= (car predicate) parse-time-elt)
+                                        (<= parse-time-elt (cadr predicate))
+                                        parse-time-elt))
+                                  ((symbolp predicate)
+                                   (cdr (assoc parse-time-elt
+                                               (symbol-value predicate))))
+                                  ((funcall predicate)))))
              (setq exit t)
              (while slots
-               (let ((new-val (and rule
-                                   (let ((this (pop rule)))
-                                     (if (vectorp this)
-                                         (parse-integer
-                                          parse-time-elt
-                                          (aref this 0) (aref this 1))
-                                       (funcall this))))))
-                 (rplaca (nthcdr (pop slots) time)
-                         (or new-val parse-time-val)))))))))
+               (let ((new-val (if rule
+                                  (let ((this (pop rule)))
+                                    (if (vectorp this)
+                                        (parse-integer
+                                         parse-time-elt
+                                         (aref this 0) (aref this 1))
+                                      (funcall this)))
+                                parse-time-val)))
+                 (rplaca (nthcdr (pop slots) time) new-val))))))))
     time))
 
+(defconst parse-time-iso8601-regexp
+  (let* ((dash "-?")
+        (colon ":?")
+        (4digit "\\([0-9][0-9][0-9][0-9]\\)")
+        (2digit "\\([0-9][0-9]\\)")
+        (date-fullyear 4digit)
+        (date-month 2digit)
+        (date-mday 2digit)
+        (time-hour 2digit)
+        (time-minute 2digit)
+        (time-second 2digit)
+        (time-secfrac "\\(\\.[0-9]+\\)?")
+        (time-numoffset (concat "[-+]\\(" time-hour "\\):" time-minute))
+        (time-offset (concat "Z" time-numoffset))
+        (partial-time (concat time-hour colon time-minute colon time-second
+                              time-secfrac))
+        (full-date (concat date-fullyear dash date-month dash date-mday))
+        (full-time (concat partial-time time-offset))
+        (date-time (concat full-date "T" full-time)))
+    (list (concat "^" full-date)
+         (concat "T" partial-time)
+         (concat "Z" time-numoffset)))
+  "List of regular expressions matching ISO 8601 dates.
+1st regular expression matches the date.
+2nd regular expression matches the time.
+3rd regular expression matches the (optional) timezone specification.")
+
+(defun parse-iso8601-time-string (date-string)
+  (let* ((date-re (nth 0 parse-time-iso8601-regexp))
+        (time-re (nth 1 parse-time-iso8601-regexp))
+        (tz-re (nth 2 parse-time-iso8601-regexp))
+        re-start
+        time seconds minute hour fractional-seconds
+        day month year day-of-week dst tz)
+    ;; We need to populate 'time' with
+    ;; (SEC MIN HOUR DAY MON YEAR DOW DST TZ)
+
+    ;; Nobody else handles iso8601 correctly, let's do it ourselves.
+    (when (string-match date-re date-string re-start)
+      (setq year (string-to-number (match-string 1 date-string))
+           month (string-to-number (match-string 2 date-string))
+           day (string-to-number (match-string 3 date-string))
+           re-start (match-end 0))
+      (when (string-match time-re date-string re-start)
+       (setq hour (string-to-number (match-string 1 date-string))
+             minute (string-to-number (match-string 2 date-string))
+             seconds (string-to-number (match-string 3 date-string))
+             fractional-seconds (string-to-number (or
+                                                    (match-string 4 date-string)
+                                                    "0"))
+             re-start (match-end 0))
+       (when (string-match tz-re date-string re-start)
+         (setq tz (match-string 1 date-string)))
+       (setq time (list seconds minute hour day month year day-of-week dst tz))))
+
+    ;; Fall back to having Gnus do fancy things for us.
+    (when (not time)
+      (setq time (parse-time-string date-string)))
+
+    (and time
+        (apply 'encode-time time))))
+
 (provide 'parse-time)
 
-;; arch-tag: 07066094-45a8-4c68-b307-86195e2c1103
 ;;; parse-time.el ends here