| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 |
|
|---|
| 24 |
|
|---|
| 25 |
|
|---|
| 26 |
|
|---|
| 27 |
|
|---|
| 28 |
|
|---|
| 29 |
|
|---|
| 30 |
|
|---|
| 31 |
|
|---|
| 32 |
|
|---|
| 33 |
|
|---|
| 34 |
|
|---|
| 35 |
|
|---|
| 36 |
|
|---|
| 37 |
|
|---|
| 38 |
|
|---|
| 39 |
|
|---|
| 40 |
(eval-when-compile (require 'cl)) |
|---|
| 41 |
|
|---|
| 42 |
(defvar parse-time-syntax (make-vector 256 nil)) |
|---|
| 43 |
(defvar parse-time-digits (make-vector 256 nil)) |
|---|
| 44 |
|
|---|
| 45 |
|
|---|
| 46 |
(defvar parse-time-elt) |
|---|
| 47 |
(defvar parse-time-val) |
|---|
| 48 |
|
|---|
| 49 |
(unless (aref parse-time-digits ?0) |
|---|
| 50 |
(loop for i from ?0 to ?9 |
|---|
| 51 |
do (aset parse-time-digits i (- i ?0)))) |
|---|
| 52 |
|
|---|
| 53 |
(unless (aref parse-time-syntax ?0) |
|---|
| 54 |
(loop for i from ?0 to ?9 |
|---|
| 55 |
do (aset parse-time-syntax i ?0)) |
|---|
| 56 |
(loop for i from ?A to ?Z |
|---|
| 57 |
do (aset parse-time-syntax i ?A)) |
|---|
| 58 |
(loop for i from ?a to ?z |
|---|
| 59 |
do (aset parse-time-syntax i ?a)) |
|---|
| 60 |
(aset parse-time-syntax ?+ 1) |
|---|
| 61 |
(aset parse-time-syntax ?- -1) |
|---|
| 62 |
(aset parse-time-syntax ?: ?d) |
|---|
| 63 |
) |
|---|
| 64 |
|
|---|
| 65 |
(defsubst digit-char-p (char) |
|---|
| 66 |
(aref parse-time-digits char)) |
|---|
| 67 |
|
|---|
| 68 |
(defsubst parse-time-string-chars (char) |
|---|
| 69 |
(and (< char (length parse-time-syntax)) |
|---|
| 70 |
(aref parse-time-syntax char))) |
|---|
| 71 |
|
|---|
| 72 |
(put 'parse-error 'error-conditions '(parse-error error)) |
|---|
| 73 |
(put 'parse-error 'error-message "Parsing error") |
|---|
| 74 |
|
|---|
| 75 |
(defsubst parse-integer (string &optional start end) |
|---|
| 76 |
"[CL] Parse and return the integer in STRING, or nil if none." |
|---|
| 77 |
(let ((integer 0) |
|---|
| 78 |
(digit 0) |
|---|
| 79 |
(index (or start 0)) |
|---|
| 80 |
(end (or end (length string)))) |
|---|
| 81 |
(when (< index end) |
|---|
| 82 |
(let ((sign (aref string index))) |
|---|
| 83 |
(if (or (eq sign ?+) (eq sign ?-)) |
|---|
| 84 |
(setq sign (parse-time-string-chars sign) |
|---|
| 85 |
index (1+ index)) |
|---|
| 86 |
(setq sign 1)) |
|---|
| 87 |
(while (and (< index end) |
|---|
| 88 |
(setq digit (digit-char-p (aref string index)))) |
|---|
| 89 |
(setq integer (+ (* integer 10) digit) |
|---|
| 90 |
index (1+ index))) |
|---|
| 91 |
(if (/= index end) |
|---|
| 92 |
(signal 'parse-error `("not an integer" |
|---|
| 93 |
,(substring string (or start 0) end))) |
|---|
| 94 |
(* sign integer)))))) |
|---|
| 95 |
|
|---|
| 96 |
(defun parse-time-tokenize (string) |
|---|
| 97 |
"Tokenize STRING into substrings." |
|---|
| 98 |
(let ((start nil) |
|---|
| 99 |
(end (length string)) |
|---|
| 100 |
(all-digits nil) |
|---|
| 101 |
(list ()) |
|---|
| 102 |
(index 0) |
|---|
| 103 |
(c nil)) |
|---|
| 104 |
(while (< index end) |
|---|
| 105 |
(while (and (< index end) |
|---|
| 106 |
(not (setq c (parse-time-string-chars (aref string index))))) |
|---|
| 107 |
(incf index)) |
|---|
| 108 |
(setq start index all-digits (eq c ?0)) |
|---|
| 109 |
(while (and (< (incf index) end) |
|---|
| 110 |
(setq c (parse-time-string-chars (aref string index)))) |
|---|
| 111 |
(setq all-digits (and all-digits (eq c ?0)))) |
|---|
| 112 |
(if (<= index end) |
|---|
| 113 |
(push (if all-digits (parse-integer string start index) |
|---|
| 114 |
(substring string start index)) |
|---|
| 115 |
list))) |
|---|
| 116 |
(nreverse list))) |
|---|
| 117 |
|
|---|
| 118 |
(defvar parse-time-months '(("jan" . 1) ("feb" . 2) ("mar" . 3) |
|---|
| 119 |
("apr" . 4) ("may" . 5) ("jun" . 6) |
|---|
| 120 |
("jul" . 7) ("aug" . 8) ("sep" . 9) |
|---|
| 121 |
("oct" . 10) ("nov" . 11) ("dec" . 12))) |
|---|
| 122 |
(defvar parse-time-weekdays '(("sun" . 0) ("mon" . 1) ("tue" . 2) |
|---|
| 123 |
("wed" . 3) ("thu" . 4) ("fri" . 5) ("sat" . 6))) |
|---|
| 124 |
(defvar parse-time-zoneinfo `(("z" 0) ("ut" 0) ("gmt" 0) |
|---|
| 125 |
("pst" ,(* -8 3600)) ("pdt" ,(* -7 3600) t) |
|---|
| 126 |
("mst" ,(* -7 3600)) ("mdt" ,(* -6 3600) t) |
|---|
| 127 |
("cst" ,(* -6 3600)) ("cdt" ,(* -5 3600) t) |
|---|
| 128 |
("est" ,(* -5 3600)) ("edt" ,(* -4 3600) t)) |
|---|
| 129 |
"(zoneinfo seconds-off daylight-savings-time-p)") |
|---|
| 130 |
|
|---|
| 131 |
(defvar parse-time-rules |
|---|
| 132 |
`(((6) parse-time-weekdays) |
|---|
| 133 |
((3) (1 31)) |
|---|
| 134 |
((4) parse-time-months) |
|---|
| 135 |
((5) (100 4038)) |
|---|
| 136 |
((2 1 0) |
|---|
| 137 |
,#'(lambda () (and (stringp parse-time-elt) |
|---|
| 138 |
(= (length parse-time-elt) 8) |
|---|
| 139 |
(= (aref parse-time-elt 2) ?:) |
|---|
| 140 |
(= (aref parse-time-elt 5) ?:))) |
|---|
| 141 |
[0 2] [3 5] [6 8]) |
|---|
| 142 |
((8 7) parse-time-zoneinfo |
|---|
| 143 |
,#'(lambda () (car parse-time-val)) |
|---|
| 144 |
,#'(lambda () (cadr parse-time-val))) |
|---|
| 145 |
((8) |
|---|
| 146 |
,#'(lambda () |
|---|
| 147 |
(and (stringp parse-time-elt) |
|---|
| 148 |
(= 5 (length parse-time-elt)) |
|---|
| 149 |
(or (= (aref parse-time-elt 0) ?+) |
|---|
| 150 |
(= (aref parse-time-elt 0) ?-)))) |
|---|
| 151 |
,#'(lambda () (* 60 (+ (parse-integer parse-time-elt 3 5) |
|---|
| 152 |
(* 60 (parse-integer parse-time-elt 1 3))) |
|---|
| 153 |
(if (= (aref parse-time-elt 0) ?-) -1 1)))) |
|---|
| 154 |
((5 4 3) |
|---|
| 155 |
,#'(lambda () (and (stringp parse-time-elt) |
|---|
| 156 |
(= (length parse-time-elt) 10) |
|---|
| 157 |
(= (aref parse-time-elt 4) ?-) |
|---|
| 158 |
(= (aref parse-time-elt 7) ?-))) |
|---|
| 159 |
[0 4] [5 7] [8 10]) |
|---|
| 160 |
((2 1 0) |
|---|
| 161 |
,#'(lambda () (and (stringp parse-time-elt) |
|---|
| 162 |
(= (length parse-time-elt) 5) |
|---|
| 163 |
(= (aref parse-time-elt 2) ?:))) |
|---|
| 164 |
[0 2] [3 5] ,#'(lambda () 0)) |
|---|
| 165 |
((2 1 0) |
|---|
| 166 |
,#'(lambda () (and (stringp parse-time-elt) |
|---|
| 167 |
(= (length parse-time-elt) 4) |
|---|
| 168 |
(= (aref parse-time-elt 1) ?:))) |
|---|
| 169 |
[0 1] [2 4] ,#'(lambda () 0)) |
|---|
| 170 |
((2 1 0) |
|---|
| 171 |
,#'(lambda () (and (stringp parse-time-elt) |
|---|
| 172 |
(= (length parse-time-elt) 7) |
|---|
| 173 |
(= (aref parse-time-elt 1) ?:))) |
|---|
| 174 |
[0 1] [2 4] [5 7]) |
|---|
| 175 |
((5) (50 110) ,#'(lambda () (+ 1900 parse-time-elt))) |
|---|
| 176 |
((5) (0 49) ,#'(lambda () (+ 2000 parse-time-elt)))) |
|---|
| 177 |
"(slots predicate extractor...)") |
|---|
| 178 |
|
|---|
| 179 |
|
|---|
| 180 |
(defun parse-time-string (string) |
|---|
| 181 |
"Parse the time-string STRING into (SEC MIN HOUR DAY MON YEAR DOW DST TZ). |
|---|
| 182 |
The values are identical to those of `decode-time', but any values that are |
|---|
| 183 |
unknown are returned as nil." |
|---|
| 184 |
(let ((time (list nil nil nil nil nil nil nil nil nil)) |
|---|
| 185 |
(temp (parse-time-tokenize (downcase string)))) |
|---|
| 186 |
(while temp |
|---|
| 187 |
(let ((parse-time-elt (pop temp)) |
|---|
| 188 |
(rules parse-time-rules) |
|---|
| 189 |
(exit nil)) |
|---|
| 190 |
(while (and (not (null rules)) (not exit)) |
|---|
| 191 |
(let* ((rule (pop rules)) |
|---|
| 192 |
(slots (pop rule)) |
|---|
| 193 |
(predicate (pop rule)) |
|---|
| 194 |
(parse-time-val)) |
|---|
| 195 |
(when (and (not (nth (car slots) time)) |
|---|
| 196 |
(setq parse-time-val (cond ((and (consp predicate) |
|---|
| 197 |
(not (eq (car predicate) |
|---|
| 198 |
'lambda))) |
|---|
| 199 |
(and (numberp parse-time-elt) |
|---|
| 200 |
(<= (car predicate) parse-time-elt) |
|---|
| 201 |
(<= parse-time-elt (cadr predicate)) |
|---|
| 202 |
parse-time-elt)) |
|---|
| 203 |
((symbolp predicate) |
|---|
| 204 |
(cdr (assoc parse-time-elt |
|---|
| 205 |
(symbol-value predicate)))) |
|---|
| 206 |
((funcall predicate))))) |
|---|
| 207 |
(setq exit t) |
|---|
| 208 |
(while slots |
|---|
| 209 |
(let ((new-val (and rule |
|---|
| 210 |
(let ((this (pop rule))) |
|---|
| 211 |
(if (vectorp this) |
|---|
| 212 |
(parse-integer |
|---|
| 213 |
parse-time-elt |
|---|
| 214 |
(aref this 0) (aref this 1)) |
|---|
| 215 |
(funcall this)))))) |
|---|
| 216 |
(rplaca (nthcdr (pop slots) time) |
|---|
| 217 |
(or new-val parse-time-val))))))))) |
|---|
| 218 |
time)) |
|---|
| 219 |
|
|---|
| 220 |
(provide 'parse-time) |
|---|
| 221 |
|
|---|
| 222 |
|
|---|
| 223 |
|
|---|
| 224 |
|
|---|