diff options
author | Leo Liu <sdl.web@gmail.com> | 2014-09-26 08:15:21 +0800 |
---|---|---|
committer | Leo Liu <sdl.web@gmail.com> | 2014-09-26 08:15:21 +0800 |
commit | 89b354a55e30978444ada5d388e18f5e06bde583 (patch) | |
tree | 0f272431b9522c96aeff74b5d262869d26c4bc3f /lisp | |
parent | b8e352d077f14c52d7e6baa1800def8d3ec61f06 (diff) | |
download | emacs-89b354a55e30978444ada5d388e18f5e06bde583.tar.gz |
Add cl-parse-integer based on parse-integer
* doc/misc/cl.texi (Predicates on Numbers): Document cl-digit-char-p.
(Numerical Functions): Document cl-parse-integer.
* lisp/calendar/parse-time.el (parse-time-digits): Remove.
(digit-char-p, parse-integer) Moved to cl-lib.el.
(parse-time-tokenize, parse-time-rules, parse-time-string): Use
cl-parse-integer.
* lisp/emacs-lisp/cl-extra.el (cl-parse-integer): New function.
* lisp/emacs-lisp/cl-lib.el (cl-digit-char-table): New var.
(cl-digit-char-p): New function.
* test/automated/cl-lib.el (cl-digit-char-p, cl-parse-integer): New
tests.
Fixes: debbugs:18557
Diffstat (limited to 'lisp')
-rw-r--r-- | lisp/ChangeLog | 13 | ||||
-rw-r--r-- | lisp/calendar/parse-time.el | 46 | ||||
-rw-r--r-- | lisp/emacs-lisp/cl-extra.el | 35 | ||||
-rw-r--r-- | lisp/emacs-lisp/cl-lib.el | 19 |
4 files changed, 74 insertions, 39 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index eb52886a4a9..4c4941d982d 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,16 @@ +2014-09-26 Leo Liu <sdl.web@gmail.com> + + Add cl-parse-integer based on parse-integer (Bug#18557) + * calendar/parse-time.el (parse-time-digits): Remove. + (digit-char-p, parse-integer) Moved to cl-lib.el. + (parse-time-tokenize, parse-time-rules, parse-time-string): Use + cl-parse-integer. + + * emacs-lisp/cl-extra.el (cl-parse-integer): New function. + + * emacs-lisp/cl-lib.el (cl-digit-char-table): New var. + (cl-digit-char-p): New function. + 2014-09-25 Juri Linkov <juri@jurta.org> * vc/add-log.el (change-log-next-buffer): Don't create an empty diff --git a/lisp/calendar/parse-time.el b/lisp/calendar/parse-time.el index 6c88210030b..142e69ecfe6 100644 --- a/lisp/calendar/parse-time.el +++ b/lisp/calendar/parse-time.el @@ -34,21 +34,12 @@ ;;; Code: -(eval-when-compile (require 'cl-lib)) - -(defvar parse-time-digits (make-vector 256 nil)) +(require 'cl-lib) ;; Byte-compiler warnings (defvar parse-time-elt) (defvar parse-time-val) -(unless (aref parse-time-digits ?0) - (cl-loop for i from ?0 to ?9 - do (aset parse-time-digits i (- i ?0)))) - -(defsubst digit-char-p (char) - (aref parse-time-digits char)) - (defsubst parse-time-string-chars (char) (save-match-data (let (case-fold-search str) @@ -59,30 +50,6 @@ ((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") - -(defsubst parse-integer (string &optional start end) - "[CL] Parse and return the integer in STRING, or nil if none." - (let ((integer 0) - (digit 0) - (index (or start 0)) - (end (or end (length string)))) - (when (< index end) - (let ((sign (aref string index))) - (if (or (eq sign ?+) (eq sign ?-)) - (setq sign (parse-time-string-chars sign) - index (1+ index)) - (setq sign 1)) - (while (and (< index end) - (setq digit (digit-char-p (aref string index)))) - (setq integer (+ (* integer 10) digit) - index (1+ index))) - (if (/= index end) - (signal 'parse-error `("not an integer" - ,(substring string (or start 0) end))) - (* sign integer)))))) - (defun parse-time-tokenize (string) "Tokenize STRING into substrings." (let ((start nil) @@ -100,7 +67,7 @@ (setq c (parse-time-string-chars (aref string index)))) (setq all-digits (and all-digits (eq c ?0)))) (if (<= index end) - (push (if all-digits (parse-integer string start index) + (push (if all-digits (cl-parse-integer string :start start :end index) (substring string start index)) list))) (nreverse list))) @@ -147,8 +114,8 @@ (= 5 (length parse-time-elt)) (or (= (aref parse-time-elt 0) ?+) (= (aref parse-time-elt 0) ?-)))) - ,#'(lambda () (* 60 (+ (parse-integer parse-time-elt 3 5) - (* 60 (parse-integer parse-time-elt 1 3))) + ,#'(lambda () (* 60 (+ (cl-parse-integer parse-time-elt :start 3 :end 5) + (* 60 (cl-parse-integer parse-time-elt :start 1 :end 3))) (if (= (aref parse-time-elt 0) ?-) -1 1)))) ((5 4 3) ,#'(lambda () (and (stringp parse-time-elt) @@ -210,9 +177,10 @@ unknown are returned as nil." (let ((new-val (if rule (let ((this (pop rule))) (if (vectorp this) - (parse-integer + (cl-parse-integer parse-time-elt - (aref this 0) (aref this 1)) + :start (aref this 0) + :end (aref this 1)) (funcall this))) parse-time-val))) (rplaca (nthcdr (pop slots) time) new-val)))))))) diff --git a/lisp/emacs-lisp/cl-extra.el b/lisp/emacs-lisp/cl-extra.el index 3761d04c2c2..c8404e0bc2d 100644 --- a/lisp/emacs-lisp/cl-extra.el +++ b/lisp/emacs-lisp/cl-extra.el @@ -383,6 +383,41 @@ With two arguments, return rounding and remainder of their quotient." "Return 1 if X is positive, -1 if negative, 0 if zero." (cond ((> x 0) 1) ((< x 0) -1) (t 0))) +;;;###autoload +(cl-defun cl-parse-integer (string &key start end radix junk-allowed) + "Parse integer from the substring of STRING from START to END. +STRING may be surrounded by whitespace chars (chars with syntax ` '). +Other non-digit chars are considered junk. +RADIX is an integer between 2 and 36, the default is 10. Signal +an error if the substring between START and END cannot be parsed +as an integer unless JUNK-ALLOWED is non-nil." + (cl-check-type string string) + (let* ((start (or start 0)) + (len (length string)) + (end (or end len)) + (radix (or radix 10))) + (or (<= start end len) + (error "Bad interval: [%d, %d)" start end)) + (cl-flet ((skip-whitespace () + (while (and (< start end) + (= 32 (char-syntax (aref string start)))) + (setq start (1+ start))))) + (skip-whitespace) + (let ((sign (cl-case (and (< start end) (aref string start)) + (?+ (cl-incf start) +1) + (?- (cl-incf start) -1) + (t +1))) + digit sum) + (while (and (< start end) + (setq digit (cl-digit-char-p (aref string start) radix))) + (setq sum (+ (* (or sum 0) radix) digit) + start (1+ start))) + (skip-whitespace) + (cond ((and junk-allowed (null sum)) sum) + (junk-allowed (* sign sum)) + ((/= start end) (error "Not an integer string: %s" string)) + (t (* sign sum))))))) + ;; Random numbers. diff --git a/lisp/emacs-lisp/cl-lib.el b/lisp/emacs-lisp/cl-lib.el index c4b9673aa2a..09cc3eee985 100644 --- a/lisp/emacs-lisp/cl-lib.el +++ b/lisp/emacs-lisp/cl-lib.el @@ -279,6 +279,25 @@ so that they are registered at compile-time as well as run-time." "Return t if INTEGER is even." (eq (logand integer 1) 0)) +(defconst cl-digit-char-table + (let* ((digits (make-vector 256 nil)) + (populate (lambda (start end base) + (mapc (lambda (i) + (aset digits i (+ base (- i start)))) + (number-sequence start end))))) + (funcall populate ?0 ?9 0) + (funcall populate ?A ?Z 10) + (funcall populate ?a ?z 10) + digits)) + +(defun cl-digit-char-p (char &optional radix) + "Test if CHAR is a digit in the specified RADIX (default 10). +If true return the decimal value of digit CHAR in RADIX." + (or (<= 2 (or radix 10) 36) + (signal 'args-out-of-range (list 'radix radix '(2 36)))) + (let ((n (aref cl-digit-char-table char))) + (and n (< n (or radix 10)) n))) + (defvar cl--random-state (vector 'cl--random-state-tag -1 30 (cl--random-time))) |