T-gnus 6.16.3 revision 00.
[elisp/gnus.git-] / lisp / gnus-clfns.el
index 9b28e89..db33634 100644 (file)
@@ -1,5 +1,6 @@
 ;;; gnus-clfns.el --- compiler macros for emulating cl functions
-;; Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+;; Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 ;; Author: Kastsumi Yamaoka <yamaoka@jpl.org>
 ;; Keywords: cl, compile
 
 ;;; Commentary:
 
-;; Avoid cl runtime functions for FSF Emacsen.
+;; This module is for mainly avoiding cl runtime functions in FSF
+;; Emacsen.  Function should also be defined as an ordinary function
+;; if it will not be provided in cl.
 
 ;;; Code:
 
 (if (featurep 'xemacs)
     nil
-  (require 'cl)
+  (eval-when-compile (require 'cl))
+  (require 'pym)
 
   (define-compiler-macro butlast (&whole form x &optional n)
-    (if (and (fboundp 'butlast)
-            (subrp (symbol-function 'butlast)))
+    (if (>= emacs-major-version 21)
        form
       (if n
          `(let ((x ,x)
                 (or n (setq n 1))
                 (and (< n m)
                      (progn
-                       (if (> n 0) (setcdr (nthcdr (- (1- m) n) x) nil))
+                       (if (> n 0)
+                           (progn
+                             (setq x (copy-sequence x))
+                             (setcdr (nthcdr (- (1- m) n) x) nil)))
                        x)))))
        `(let* ((x ,x)
                (m (length x)))
           (and (< 1 m)
                (progn
+                 (setq x (copy-sequence x))
                  (setcdr (nthcdr (- m 2) x) nil)
                  x))))))
 
+;;  (define-compiler-macro coerce (&whole form x type)
+;;    (if (and (fboundp 'coerce)
+;;          (subrp (symbol-function 'coerce)))
+;;     form
+;;      `(let ((x ,x)
+;;          (type ,type))
+;;      (cond ((eq type 'list) (if (listp x) x (append x nil)))
+;;            ((eq type 'vector) (if (vectorp x) x (vconcat x)))
+;;            ((eq type 'string) (if (stringp x) x (concat x)))
+;;            ((eq type 'array) (if (arrayp x) x (vconcat x)))
+;;            ((and (eq type 'character) (stringp x) (= (length x) 1))
+;;             (aref x 0))
+;;            ((and (eq type 'character) (symbolp x)
+;;                  (= (length (symbol-name x)) 1))
+;;             (aref (symbol-name x) 0))
+;;            ((eq type 'float) (float x))
+;;            ((typep x type) x)
+;;            (t (error "Can't coerce %s to type %s" x type))))))
+
+;;  (define-compiler-macro copy-list (&whole form list)
+;;    (if (and (fboundp 'copy-list)
+;;          (subrp (symbol-function 'copy-list)))
+;;     form
+;;      `(let ((list ,list))
+;;      (if (consp list)
+;;          (let ((res nil))
+;;            (while (consp list) (push (pop list) res))
+;;            (prog1 (nreverse res) (setcdr res list)))
+;;        (car list)))))
+
   (define-compiler-macro last (&whole form x &optional n)
-    (if (and (fboundp 'last)
-            (subrp (symbol-function 'last)))
+    (if (>= emacs-major-version 20)
        form
       (if n
          `(let* ((x ,x)
           (while (consp (cdr x))
             (pop x))
           x))))
+
+  (define-compiler-macro mapc (&whole form fn seq &rest rest)
+    (if (>= emacs-major-version 21)
+       form
+      (if rest
+         `(let* ((fn ,fn)
+                 (seq ,seq)
+                 (args (list seq ,@rest))
+                 (m (apply (function min) (mapcar (function length) args)))
+                 (n 0))
+            (while (< n m)
+              (apply fn (mapcar (function (lambda (arg) (nth n arg))) args))
+              (setq n (1+ n)))
+            seq)
+       `(let ((seq ,seq))
+          (mapcar ,fn seq)
+          seq))))
+
+;;  (define-compiler-macro merge (&whole form type seq1 seq2 pred &rest keys)
+;;    (if (and (fboundp 'merge)
+;;          (subrp (symbol-function 'merge)))
+;;     form
+;;      `(let ((type ,type)
+;;          (seq1 ,seq1)
+;;          (seq2 ,seq2)
+;;          (pred ,pred))
+;;      (or (listp seq1) (setq seq1 (append seq1 nil)))
+;;      (or (listp seq2) (setq seq2 (append seq2 nil)))
+;;      (let ((res nil))
+;;        (while (and seq1 seq2)
+;;          (if (funcall pred (car seq2) (car seq1))
+;;              (push (pop seq2) res)
+;;            (push (pop seq1) res)))
+;;        (coerce (nconc (nreverse res) seq1 seq2) type)))))
+
+;;  (define-compiler-macro string (&whole form &rest args)
+;;    (if (>= emacs-major-version 20)
+;;     form
+;;      (list 'concat (cons 'list args))))
+
+;;  (defun-maybe string (&rest args)
+;;    "Concatenate all the argument characters and make the result a string."
+;;    (concat args))
+
+  (define-compiler-macro string-to-list (&whole form string)
+    (cond ((fboundp 'string-to-list)
+          form)
+         ((fboundp 'string-to-char-list)
+          (list 'string-to-char-list string))
+         (t
+          `(let* ((str ,string)
+                  (len (length str))
+                  (idx 0)
+                  c l)
+             (while (< idx len)
+               (setq c (sref str idx))
+               (setq idx (+ idx (char-bytes c)))
+               (setq l (cons c l)))
+             (nreverse l)))))
+
+  ;; 92.7.2 by K.Handa (imported from Mule 2.3)
+  (defun-maybe string-to-list (str)
+    (let ((len (length str))
+         (idx 0)
+         c l)
+      (while (< idx len)
+       (setq c (sref str idx))
+       (setq idx (+ idx (char-bytes c)))
+       (setq l (cons c l)))
+      (nreverse l)))
+
+;;  (define-compiler-macro subseq (&whole form seq start &optional end)
+;;    (if (and (fboundp 'subseq)
+;;          (subrp (symbol-function 'subseq)))
+;;     form
+;;      (if end
+;;       `(let ((seq ,seq)
+;;              (start ,start)
+;;              (end ,end))
+;;          (if (stringp seq)
+;;              (substring seq start end)
+;;            (let (len)
+;;              (if (< end 0)
+;;                  (setq end (+ end (setq len (length seq)))))
+;;              (if (< start 0)
+;;                  (setq start (+ start (or len (setq len (length seq))))))
+;;              (cond ((listp seq)
+;;                     (if (> start 0)
+;;                         (setq seq (nthcdr start seq)))
+;;                     (let ((res nil))
+;;                       (while (>= (setq end (1- end)) start)
+;;                         (push (pop seq) res))
+;;                       (nreverse res)))
+;;                    (t
+;;                     (let ((res (make-vector (max (- end start) 0) nil))
+;;                           (i 0))
+;;                       (while (< start end)
+;;                         (aset res i (aref seq start))
+;;                         (setq i (1+ i)
+;;                               start (1+ start)))
+;;                       res))))))
+;;     `(let ((seq ,seq)
+;;            (start ,start))
+;;        (if (stringp seq)
+;;            (substring seq start)
+;;          (let (len)
+;;            (if (< start 0)
+;;                (setq start (+ start (or len (setq len (length seq))))))
+;;            (cond ((listp seq)
+;;                   (if (> start 0)
+;;                       (setq seq (nthcdr start seq)))
+;;                   (copy-sequence seq))
+;;                  (t
+;;                   (let* ((end (or len (length seq)))
+;;                          (res (make-vector (max (- end start) 0) nil))
+;;                          (i 0))
+;;                     (while (< start end)
+;;                       (aset res i (aref seq start))
+;;                       (setq i (1+ i)
+;;                             start (1+ start)))
+;;                     res)))))))))
   )
 
+;; A tool for the developers.
+
+(defvar cl-run-time-functions
+  '(Values
+    Values-list acons assoc-if assoc-if-not build-klist butlast ceiling*
+    coerce common-lisp-indent-function compiler-macroexpand concatenate
+    copy-list count count-if count-if-not delete* delete-duplicates delete-if
+    delete-if-not duplicate-symbols-p elt-satisfies-test-p equalp evenp every
+    extract-from-klist fill find find-if find-if-not floatp-safe floor* gcd
+    gensym gentemp get-setf-method getf hash-table-count hash-table-p
+    intersection isqrt keyword-argument-supplied-p keyword-of keywordp last
+    lcm ldiff lisp-indent-259 lisp-indent-do lisp-indent-function-lambda-hack
+    lisp-indent-report-bad-format lisp-indent-tagbody list-length
+    make-hash-table make-random-state map mapc mapcan mapcar* mapcon mapl
+    maplist member-if member-if-not merge mismatch mod* nbutlast nintersection
+    notany notevery nreconc nset-difference nset-exclusive-or nsublis nsubst
+    nsubst-if nsubst-if-not nsubstitute nsubstitute-if nsubstitute-if-not
+    nunion oddp pair-with-newsyms pairlis position position-if position-if-not
+    proclaim random* random-state-p rassoc* rassoc-if rassoc-if-not
+    reassemble-argslists reduce rem* remove remove* remove-duplicates
+    remove-if remove-if-not remq replace revappend round* safe-idiv search
+    set-difference set-exclusive-or setelt setnth setnthcdr signum some sort*
+    stable-sort sublis subseq subsetp subst subst-if subst-if-not substitute
+    substitute-if substitute-if-not tailp tree-equal truncate* union
+    unzip-lists zip-lists)
+  "A list of CL run-time functions.  Some functions were built-in, nowadays.")
+
+;;;###autoload
+(defun find-cl-run-time-functions (file-or-directory arg)
+  "Find CL run-time functions in the FILE-OR-DIRECTORY.  You can alter
+the behavior of this command with the prefix ARG as described below.
+
+By default, it searches for all the CL run-time functions listed in
+ the variable `cl-run-time-functions'.
+With 1 or 3 \\[universal-argument]'s, the built-in functions in this Emacs\
+ will not be
+ reported.
+With 2 or 3 \\[universal-argument]'s, just the symbols will also be reported.
+
+You can use the `digit-argument' 1, 2 or 3 instead of\
+ \\[universal-argument]'s."
+  (interactive (list (read-file-name "Find CL run-time functions in: "
+                                    nil default-directory t)
+                    current-prefix-arg))
+  (unless (interactive-p)
+    (error "You should invoke `M-x find-cl-run-time-functions' interactively"))
+  (let ((report-symbols (member arg '((16) (64) 2 3)))
+       files clfns working file lines form forms fns fn newform buffer
+       window scroll
+       buffer-file-format format-alist
+       insert-file-contents-post-hook insert-file-contents-pre-hook)
+    (cond ((file-directory-p file-or-directory)
+          (setq files (directory-files file-or-directory t "\\.el$"))
+          (dolist (file files)
+            (unless (file-exists-p file)
+              (setq files (delete file files))))
+          (unless files
+            (message "No files found in: %s" file-or-directory))
+          files)
+         ((file-exists-p file-or-directory)
+          (setq files (list file-or-directory)))
+         (t
+          (message "No such file or directory: %s" file-or-directory)))
+    (when files
+      (if (member arg '((4) (64) 1 3))
+         (dolist (fn cl-run-time-functions)
+           (unless (and (fboundp fn)
+                        (subrp (symbol-function fn)))
+             (push fn clfns)))
+       (setq clfns cl-run-time-functions))
+      (set-buffer (setq working
+                       (get-buffer-create
+                        " *Searching for CL run-time functions*")))
+      (let (emacs-lisp-mode-hook)
+       (emacs-lisp-mode))
+      (while files
+       (setq file (pop files)
+             lines (list nil nil))
+       (message "Searching for CL run-time functions in: %s..."
+                (file-name-nondirectory file))
+       (insert-file-contents file nil nil nil t)
+       ;; XEmacs moves point to the beginning of the buffer after
+       ;; inserting a file, FSFmacs doesn't so if the fifth argument
+       ;; of `insert-file-contents' is specified.
+       (goto-char (point-min))
+       ;;
+       (while (progn
+                (while (and (looking-at "[\t\v\f\r ]*\\(;.*\\)?$")
+                            (zerop (forward-line 1))))
+                (not (eobp)))
+         (setcar lines (if (bolp)
+                           (1+ (count-lines (point-min) (point)))
+                         (count-lines (point-min) (point))))
+         (when (consp;; Ignore stand-alone symbols, strings, etc.
+                (setq form (condition-case nil
+                               (read working)
+                             (error nil))))
+           (setcdr lines (list (count-lines (point-min) (point))))
+           (setq forms (list form)
+                 fns nil)
+           (while forms
+             (setq form (pop forms))
+             (when (consp form)
+               (setq fn (pop form))
+               (cond ((memq fn '(apply mapatoms mapcar mapconcat
+                                       mapextent symbol-function))
+                      (if (consp (car form))
+                          (when (memq (caar form) '(\` backquote quote))
+                            (setcar form (cdar form)))
+                        (setq form (cdr form))))
+                     ((memq fn '(\` backquote quote))
+                      (if report-symbols
+                          (progn
+                            (setq form (car form)
+                                  newform nil)
+                            (while form
+                              (push (list (or (car-safe form) form))
+                                    newform)
+                              (setq form (cdr-safe form)))
+                            (setq form (nreverse newform)))
+                        (setq form nil)))
+                     ((memq fn '(defadvice
+                                  defmacro defsubst defun
+                                  defmacro-maybe defmacro-maybe-cond
+                                  defsubst-maybe defun-maybe
+                                  defun-maybe-cond))
+                      (setq form (cddr form)))
+                     ((memq fn '(defalias lambda fset))
+                      (setq form (cdr form)))
+                     ((eq fn 'define-compiler-macro)
+                      (setq form nil))
+                     ((eq fn 'dolist)
+                      (setcar form (cadar form)))
+                     ((memq fn '(let let*))
+                      (setq form
+                            (append
+                             (delq nil
+                                   (mapcar
+                                    (lambda (element)
+                                      (when (and (consp element)
+                                                 (consp (cadr element)))
+                                        (cadr element)))
+                                    (car form)))
+                             (cdr form))))
+                     ((eq fn 'sort)
+                      (when (and (consp (cadr form))
+                                 (memq (caadr form) '(\` backquote quote)))
+                        (setcdr form (list (cdadr form)))))
+                     ((and (memq fn clfns)
+                           (listp form))
+                      (push fn fns)))
+               (when (listp form)
+                 (setq forms (append form forms)))))
+           (when fns
+             (if buffer
+                 (set-buffer buffer)
+               (display-buffer
+                (setq buffer (get-buffer-create
+                              (concat "*CL run-time functions in: "
+                                      file-or-directory "*"))))
+               (set-buffer buffer)
+               (erase-buffer)
+               (setq window (get-buffer-window buffer t)
+                     scroll (- 2 (window-height window))
+                     fill-column (max 16 (- (window-width window) 2))
+                     fill-prefix "               "))
+             (when file
+               (insert file "\n")
+               (setq file nil))
+             (narrow-to-region
+              (point)
+              (progn
+                (insert fill-prefix
+                        (mapconcat (lambda (fn) (format "%s" fn))
+                                   (nreverse fns) " ")
+                        "\n")
+                (point)))
+             (fill-region (point-min) (point-max))
+             (goto-char (point-min))
+             (widen)
+             (delete-char 14)
+             (insert (format "%5d - %5d:" (car lines) (cadr lines)))
+             (goto-char (point-max))
+             (forward-line scroll)
+             (set-window-start window (point))
+             (goto-char (point-max))
+             (sit-for 0)
+             (set-buffer working)))))
+      (kill-buffer working)
+      (if buffer
+         (message "Done")
+       (message "No CL run-time functions found in: %s"
+                file-or-directory)))))
+
 (provide 'gnus-clfns)
 
 ;;; gnus-clfns.el ends here