*** empty log message *** semi21-2000-08-12
authorhanda <handa>
Sat, 12 Aug 2000 02:45:46 +0000 (02:45 +0000)
committerhanda <handa>
Sat, 12 Aug 2000 02:45:46 +0000 (02:45 +0000)
emacs-lisp/alist.el [new file with mode: 0644]
emacs-lisp/calist.el [new file with mode: 0644]
emacs-lisp/filename.el [new file with mode: 0644]
emacs-lisp/install.el [new file with mode: 0644]
emacs-lisp/path-util.el [new file with mode: 0644]
mail/smtp.el [new file with mode: 0644]
richtext.el [new file with mode: 0644]

diff --git a/emacs-lisp/alist.el b/emacs-lisp/alist.el
new file mode 100644 (file)
index 0000000..4ac3169
--- /dev/null
@@ -0,0 +1,120 @@
+;;; alist.el --- utility functions about association-list
+
+;; Copyright (C) 1993,1994,1995,1996,1998,2000 Free Software Foundation, Inc.
+
+;; Author: MORIOKA Tomohiko <tomo@m17n.org>
+;; Keywords: alist
+
+;; This file is part of APEL (A Portable Emacs Library).
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Code:
+
+;;;###autoload
+(defun put-alist (item value alist)
+  "Modify ALIST to set VALUE to ITEM.
+If there is a pair whose car is ITEM, replace its cdr by VALUE.
+If there is not such pair, create new pair (ITEM . VALUE) and
+return new alist whose car is the new pair and cdr is ALIST.
+\[tomo's ELIS like function]"
+  (let ((pair (assoc item alist)))
+    (if pair
+       (progn
+         (setcdr pair value)
+         alist)
+      (cons (cons item value) alist)
+      )))
+
+;;;###autoload
+(defun del-alist (item alist)
+  "If there is a pair whose key is ITEM, delete it from ALIST.
+\[tomo's ELIS emulating function]"
+  (if (equal item (car (car alist)))
+      (cdr alist)
+    (let ((pr alist)
+         (r (cdr alist))
+         )
+      (catch 'tag
+       (while (not (null r))
+         (if (equal item (car (car r)))
+             (progn
+               (rplacd pr (cdr r))
+               (throw 'tag alist)))
+         (setq pr r)
+         (setq r (cdr r))
+         )
+       alist))))
+
+;;;###autoload
+(defun set-alist (symbol item value)
+  "Modify a alist indicated by SYMBOL to set VALUE to ITEM."
+  (or (boundp symbol)
+      (set symbol nil)
+      )
+  (set symbol (put-alist item value (symbol-value symbol)))
+  )
+
+;;;###autoload
+(defun remove-alist (symbol item)
+  "Remove ITEM from the alist indicated by SYMBOL."
+  (and (boundp symbol)
+       (set symbol (del-alist item (symbol-value symbol)))
+       ))
+
+;;;###autoload
+(defun modify-alist (modifier default)
+  "Modify alist DEFAULT into alist MODIFIER."
+  (mapcar (function
+          (lambda (as)
+            (setq default (put-alist (car as)(cdr as) default))
+            ))
+         modifier)
+  default)
+
+;;;###autoload
+(defun set-modified-alist (sym modifier)
+  "Modify a value of a symbol SYM into alist MODIFIER.
+The symbol SYM should be alist. If it is not bound,
+its value regard as nil."
+  (if (not (boundp sym))
+      (set sym nil)
+    )
+  (set sym (modify-alist modifier (eval sym)))
+  )
+
+
+;;; @ association-vector-list
+;;;
+
+;;;###autoload
+(defun vassoc (key avlist)
+  "Search AVLIST for a vector whose first element is equal to KEY.
+See also `assoc'."
+  (let (v)
+    (while (and (setq v (car avlist))
+               (not (equal key (aref v 0))))
+      (setq avlist (cdr avlist)))
+    v))
+
+
+;;; @ end
+;;;
+
+(require 'product)
+(product-provide (provide 'alist) (require 'apel-ver))
+
+;;; alist.el ends here
diff --git a/emacs-lisp/calist.el b/emacs-lisp/calist.el
new file mode 100644 (file)
index 0000000..fbef680
--- /dev/null
@@ -0,0 +1,331 @@
+;;; calist.el --- Condition functions
+
+;; Copyright (C) 1998 Free Software Foundation, Inc.
+;; Copyright (C) 1999 Electrotechnical Laboratory, JAPAN.
+;; Licensed to the Free Software Foundation.
+
+;; Author: MORIOKA Tomohiko <tomo@m17n.org>
+;; Keywords: condition, alist, tree
+
+;; This file is part of APEL (A Portable Emacs Library).
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'alist)
+
+(defvar calist-package-alist nil)
+(defvar calist-field-match-method-obarray nil)
+
+(defun find-calist-package (name)
+  "Return a calist-package by NAME."
+  (cdr (assq name calist-package-alist)))
+
+(defun define-calist-field-match-method (field-type function)
+  "Set field-match-method for FIELD-TYPE to FUNCTION."
+  (fset (intern (symbol-name field-type) calist-field-match-method-obarray)
+       function))
+
+(defun use-calist-package (name)
+  "Make the symbols of package NAME accessible in the current package."
+  (mapatoms (lambda (sym)
+             (if (intern-soft (symbol-name sym)
+                              calist-field-match-method-obarray)
+                 (signal 'conflict-of-calist-symbol
+                         (list (format "Conflict of symbol %s")))
+               (if (fboundp sym)
+                   (define-calist-field-match-method
+                     sym (symbol-function sym))
+                 )))
+           (find-calist-package name)))
+
+(defun make-calist-package (name &optional use)
+  "Create a new calist-package."
+  (let ((calist-field-match-method-obarray (make-vector 7 0)))
+    (set-alist 'calist-package-alist name
+              calist-field-match-method-obarray)
+    (use-calist-package (or use 'standard))
+    calist-field-match-method-obarray))
+
+(defun in-calist-package (name)
+  "Set the current calist-package to a new or existing calist-package."
+  (setq calist-field-match-method-obarray
+       (or (find-calist-package name)
+           (make-calist-package name))))
+
+(in-calist-package 'standard)
+
+(defun calist-default-field-match-method (calist field-type field-value)
+  (let ((s-field (assoc field-type calist)))
+    (cond ((null s-field)
+          (cons (cons field-type field-value) calist)
+          )
+         ((eq field-value t)
+          calist)
+         ((equal (cdr s-field) field-value)
+          calist))))
+
+(define-calist-field-match-method t (function calist-default-field-match-method))
+
+(defsubst calist-field-match-method (field-type)
+  (symbol-function
+   (or (intern-soft (if (symbolp field-type)
+                       (symbol-name field-type)
+                     field-type)
+                   calist-field-match-method-obarray)
+       (intern-soft "t" calist-field-match-method-obarray))))
+
+(defsubst calist-field-match (calist field-type field-value)
+  (funcall (calist-field-match-method field-type)
+          calist field-type field-value))
+
+(defun ctree-match-calist (rule-tree alist)
+  "Return matched condition-alist if ALIST matches RULE-TREE."
+  (if (null rule-tree)
+      alist
+    (let ((type (car rule-tree))
+         (choices (cdr rule-tree))
+         default)
+      (catch 'tag
+       (while choices
+         (let* ((choice (car choices))
+                (choice-value (car choice)))
+           (if (eq choice-value t)
+               (setq default choice)
+             (let ((ret-alist (calist-field-match alist type (car choice))))
+               (if ret-alist
+                   (throw 'tag
+                          (if (cdr choice)
+                              (ctree-match-calist (cdr choice) ret-alist)
+                            ret-alist))
+                 ))))
+         (setq choices (cdr choices)))
+       (if default
+           (let ((ret-alist (calist-field-match alist type t)))
+             (if ret-alist
+                 (if (cdr default)
+                     (ctree-match-calist (cdr default) ret-alist)
+                   ret-alist))))
+       ))))
+
+(defun ctree-match-calist-partially (rule-tree alist)
+  "Return matched condition-alist if ALIST matches RULE-TREE."
+  (if (null rule-tree)
+      alist
+    (let ((type (car rule-tree))
+         (choices (cdr rule-tree))
+         default)
+      (catch 'tag
+       (while choices
+         (let* ((choice (car choices))
+                (choice-value (car choice)))
+           (if (eq choice-value t)
+               (setq default choice)
+             (let ((ret-alist (calist-field-match alist type (car choice))))
+               (if ret-alist
+                   (throw 'tag
+                          (if (cdr choice)
+                              (ctree-match-calist-partially
+                               (cdr choice) ret-alist)
+                            ret-alist))
+                 ))))
+         (setq choices (cdr choices)))
+       (if default
+           (let ((ret-alist (calist-field-match alist type t)))
+             (if ret-alist
+                 (if (cdr default)
+                     (ctree-match-calist-partially (cdr default) ret-alist)
+                   ret-alist)))
+         (calist-field-match alist type t))
+       ))))
+
+(defun ctree-find-calist (rule-tree alist &optional all)
+  "Return list of condition-alist which matches ALIST in RULE-TREE.
+If optional argument ALL is specified, default rules are not ignored
+even if other rules are matched for ALIST."
+  (if (null rule-tree)
+      (list alist)
+    (let ((type (car rule-tree))
+         (choices (cdr rule-tree))
+         default dest)
+      (while choices
+       (let* ((choice (car choices))
+              (choice-value (car choice)))
+         (if (eq choice-value t)
+             (setq default choice)
+           (let ((ret-alist (calist-field-match alist type (car choice))))
+             (if ret-alist
+                 (if (cdr choice)
+                     (let ((ret (ctree-find-calist
+                                 (cdr choice) ret-alist all)))
+                       (while ret
+                         (let ((elt (car ret)))
+                           (or (member elt dest)
+                               (setq dest (cons elt dest))
+                               ))
+                         (setq ret (cdr ret))
+                         ))
+                   (or (member ret-alist dest)
+                       (setq dest (cons ret-alist dest)))
+                   )))))
+       (setq choices (cdr choices)))
+      (or (and (not all) dest)
+         (if default
+             (let ((ret-alist (calist-field-match alist type t)))
+               (if ret-alist
+                   (if (cdr default)
+                       (let ((ret (ctree-find-calist
+                                   (cdr default) ret-alist all)))
+                         (while ret
+                           (let ((elt (car ret)))
+                             (or (member elt dest)
+                                 (setq dest (cons elt dest))
+                                 ))
+                           (setq ret (cdr ret))
+                           ))
+                     (or (member ret-alist dest)
+                         (setq dest (cons ret-alist dest)))
+                     ))))
+         )
+      dest)))
+
+(defun calist-to-ctree (calist)
+  "Convert condition-alist CALIST to condition-tree."
+  (if calist
+      (let* ((cell (car calist)))
+       (cons (car cell)
+             (list (cons (cdr cell)
+                         (calist-to-ctree (cdr calist))
+                         ))))))
+
+(defun ctree-add-calist-strictly (ctree calist)
+  "Add condition CALIST to condition-tree CTREE without default clause."
+  (cond ((null calist) ctree)
+       ((null ctree)
+        (calist-to-ctree calist)
+        )
+       (t
+        (let* ((type (car ctree))
+               (values (cdr ctree))
+               (ret (assoc type calist)))
+          (if ret
+              (catch 'tag
+                (while values
+                  (let ((cell (car values)))
+                    (if (equal (car cell)(cdr ret))
+                        (throw 'tag
+                               (setcdr cell
+                                       (ctree-add-calist-strictly
+                                        (cdr cell)
+                                        (delete ret (copy-alist calist)))
+                                       ))))
+                  (setq values (cdr values)))
+                (setcdr ctree (cons (cons (cdr ret)
+                                          (calist-to-ctree
+                                           (delete ret (copy-alist calist))))
+                                    (cdr ctree)))
+                )
+            (catch 'tag
+              (while values
+                (let ((cell (car values)))
+                  (setcdr cell
+                          (ctree-add-calist-strictly (cdr cell) calist))
+                  )
+                (setq values (cdr values))))
+            )
+          ctree))))
+
+(defun ctree-add-calist-with-default (ctree calist)
+  "Add condition CALIST to condition-tree CTREE with default clause."
+  (cond ((null calist) ctree)
+       ((null ctree)
+        (let* ((cell (car calist))
+               (type (car cell))
+               (value (cdr cell)))
+          (cons type
+                (list (list t)
+                      (cons value (calist-to-ctree (cdr calist)))))
+          ))
+       (t
+        (let* ((type (car ctree))
+               (values (cdr ctree))
+               (ret (assoc type calist)))
+          (if ret
+              (catch 'tag
+                (while values
+                  (let ((cell (car values)))
+                    (if (equal (car cell)(cdr ret))
+                        (throw 'tag
+                               (setcdr cell
+                                       (ctree-add-calist-with-default
+                                        (cdr cell)
+                                        (delete ret (copy-alist calist)))
+                                       ))))
+                  (setq values (cdr values)))
+                (if (assq t (cdr ctree))
+                    (setcdr ctree
+                            (cons (cons (cdr ret)
+                                        (calist-to-ctree
+                                         (delete ret (copy-alist calist))))
+                                  (cdr ctree)))
+                  (setcdr ctree
+                          (list* (list t)
+                                 (cons (cdr ret)
+                                       (calist-to-ctree
+                                        (delete ret (copy-alist calist))))
+                                 (cdr ctree)))
+                  ))
+            (catch 'tag
+              (while values
+                (let ((cell (car values)))
+                  (setcdr cell
+                          (ctree-add-calist-with-default (cdr cell) calist))
+                  )
+                (setq values (cdr values)))
+              (let ((cell (assq t (cdr ctree))))
+                (if cell
+                    (setcdr cell
+                            (ctree-add-calist-with-default (cdr cell)
+                                                           calist))
+                  (let ((elt (cons t (calist-to-ctree calist))))
+                    (or (member elt (cdr ctree))
+                        (setcdr ctree (cons elt (cdr ctree)))
+                        ))
+                  )))
+            )
+          ctree))))
+
+(defun ctree-set-calist-strictly (ctree-var calist)
+  "Set condition CALIST in CTREE-VAR without default clause."
+  (set ctree-var
+       (ctree-add-calist-strictly (symbol-value ctree-var) calist)))
+
+(defun ctree-set-calist-with-default (ctree-var calist)
+  "Set condition CALIST to CTREE-VAR with default clause."
+  (set ctree-var
+       (ctree-add-calist-with-default (symbol-value ctree-var) calist)))
+
+
+;;; @ end
+;;;
+
+(require 'product)
+(product-provide (provide 'calist) (require 'apel-ver))
+
+;;; calist.el ends here
diff --git a/emacs-lisp/filename.el b/emacs-lisp/filename.el
new file mode 100644 (file)
index 0000000..ea11042
--- /dev/null
@@ -0,0 +1,153 @@
+;;; filename.el --- file name filter
+
+;; Copyright (C) 1996,1997 MORIOKA Tomohiko
+
+;; Author: MORIOKA Tomohiko <morioka@jaist.ac.jp>
+;; Version: $Id: filename.el,v 1.1.2.1 2000/02/03 02:26:43 tomo Exp $
+;; Keywords: file name, string
+
+;; This file is part of APEL (A Portable Emacs Library).
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Code:
+
+(require 'emu)                         ; for backward compatibility.
+(require 'poe)                         ; functionp.
+(require 'poem)                                ; char-int, and char-length.
+(require 'path-util)
+
+(defsubst poly-funcall (functions argument)
+  "Apply initial ARGUMENT to sequence of FUNCTIONS.
+FUNCTIONS is list of functions.
+
+(poly-funcall '(f1 f2 .. fn) arg) is as same as
+(fn .. (f2 (f1 arg)) ..).
+
+For example, (poly-funcall '(car number-to-string) '(100)) returns
+\"100\"."
+  (while functions
+    (setq argument (funcall (car functions) argument)
+         functions (cdr functions)))
+  argument)
+
+
+;;; @ variables
+;;;
+
+(defvar filename-limit-length 21 "Limit size of file-name.")
+
+(defvar filename-replacement-alist
+  '(((?\  ?\t) . "_")
+    ((?! ?\" ?# ?$ ?% ?& ?' ?\( ?\) ?* ?/
+        ?: ?\; ?< ?> ?? ?\[ ?\\ ?\] ?` ?{ ?| ?}) . "_")
+    (filename-control-p . ""))
+  "Alist list of characters vs. string as replacement.
+List of characters represents characters not allowed as file-name.")
+
+(defvar filename-filters
+  (let ((filters '(filename-special-filter
+                  filename-eliminate-top-low-lines
+                  filename-canonicalize-low-lines
+                  filename-maybe-truncate-by-size
+                  filename-eliminate-bottom-low-lines
+                  )))
+    (if (exec-installed-p "kakasi")
+       (cons 'filename-japanese-to-roman-string filters)
+      filters))
+  "List of functions for file-name filter.")
+
+
+;;; @ filters
+;;;
+
+(defun filename-japanese-to-roman-string (str)
+  (save-excursion
+    (set-buffer (get-buffer-create " *temp kakasi*"))
+    (erase-buffer)
+    (insert str)
+    (call-process-region
+     (point-min)(point-max)
+     "kakasi" t t t "-Ha" "-Ka" "-Ja" "-Ea" "-ka")
+    (buffer-string)))
+
+(defun filename-control-p (character)
+  (let ((code (char-int character)))
+    (or (< code 32)(= code 127))))
+
+(defun filename-special-filter (string)
+  (let ((len (length string))
+       (b 0)(i 0)
+       (dest ""))
+    (while (< i len)
+      (let ((chr (sref string i))
+            (lst filename-replacement-alist)
+            ret)
+        (while (and lst (not ret))
+          (if (if (functionp (car (car lst)))
+                  (setq ret (funcall (car (car lst)) chr))
+                (setq ret (memq chr (car (car lst)))))
+              t                         ; quit this loop.
+            (setq lst (cdr lst))))
+       (if ret
+           (setq dest (concat dest (substring string b i)(cdr (car lst)))
+                 i (+ i (char-length chr))
+                 b i)
+         (setq i (+ i (char-length chr))))))
+    (concat dest (substring string b))))
+
+(defun filename-eliminate-top-low-lines (string)
+  (if (string-match "^_+" string)
+      (substring string (match-end 0))
+    string))
+
+(defun filename-canonicalize-low-lines (string)
+  (let ((dest ""))
+    (while (string-match "__+" string)
+      (setq dest (concat dest (substring string 0 (1+ (match-beginning 0)))))
+      (setq string (substring string (match-end 0))))
+    (concat dest string)))
+
+(defun filename-maybe-truncate-by-size (string)
+  (if (and (> (length string) filename-limit-length)
+          (string-match "_" string filename-limit-length))
+      (substring string 0 (match-beginning 0))
+    string))
+
+(defun filename-eliminate-bottom-low-lines (string)
+  (if (string-match "_+$" string)
+      (substring string 0 (match-beginning 0))
+    string))
+
+
+;;; @ interface
+;;;
+
+(defun replace-as-filename (string)
+  "Return safety filename from STRING.
+It refers variable `filename-filters' and default filters refers
+`filename-limit-length', `filename-replacement-alist'."
+  (and string
+       (poly-funcall filename-filters string)))
+
+
+;;; @ end
+;;;
+
+(require 'product)
+(product-provide (provide 'filename) (require 'apel-ver))
+
+;;; filename.el ends here
diff --git a/emacs-lisp/install.el b/emacs-lisp/install.el
new file mode 100644 (file)
index 0000000..2d9dd41
--- /dev/null
@@ -0,0 +1,200 @@
+;;; install.el --- Emacs Lisp package install utility
+
+;; Copyright (C) 1996,1997,1998,1999 Free Software Foundation, Inc.
+
+;; Author: MORIOKA Tomohiko <morioka@jaist.ac.jp>
+;; Created: 1996/08/18
+;; Keywords: install, byte-compile, directory detection
+
+;; This file is part of APEL (A Portable Emacs Library).
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Code:
+
+(require 'poe)                         ; make-directory for v18
+(require 'path-util)                   ; default-load-path
+
+
+;;; @ compile Emacs Lisp files
+;;;
+
+(defun compile-elisp-module (module &optional path every-time)
+  (setq module (expand-file-name (symbol-name module) path))
+  (let ((el-file (concat module ".el"))
+       (elc-file (concat module ".elc")))
+    (if (or every-time
+           (file-newer-than-file-p el-file elc-file))
+       (byte-compile-file el-file))))
+
+(defun compile-elisp-modules (modules &optional path every-time)
+  (mapcar
+   (function
+    (lambda (module)
+      (compile-elisp-module module path every-time)))
+   modules))
+
+
+;;; @ install files
+;;;
+
+(defvar install-overwritten-file-modes (+ (* 64 6)(* 8 4) 4)) ; 0644
+
+(defun install-file (file src dest &optional move overwrite just-print)
+  (if just-print
+      (princ (format "%s -> %s\n" file dest))
+    (let ((src-file (expand-file-name file src)))
+      (if (file-exists-p src-file)
+         (let ((full-path (expand-file-name file dest)))
+           (if (and (file-exists-p full-path) overwrite)
+               (delete-file full-path))
+           (copy-file src-file full-path t t)
+           (if move
+               (catch 'tag
+                 (while (and (file-exists-p src-file)
+                             (file-writable-p src-file))
+                   (condition-case err
+                       (progn
+                         (delete-file src-file)
+                         (throw 'tag nil))
+                     (error (princ (format "%s\n" (nth 1 err))))))))
+           (princ (format "%s -> %s\n" file dest)))))))
+
+(defun install-files (files src dest &optional move overwrite just-print)
+  (or (file-exists-p dest)
+      (make-directory dest t))
+  (mapcar
+   (function
+    (lambda (file)
+      (install-file file src dest move overwrite just-print)))
+   files))
+
+
+;;; @@ install Emacs Lisp files
+;;;
+
+(defun install-elisp-module (module src dest &optional just-print)
+  (let (el-file elc-file)
+    (let ((name (symbol-name module)))
+      (setq el-file (concat name ".el"))
+      (setq elc-file (concat name ".elc")))
+    (let ((src-file (expand-file-name el-file src)))
+      (if (not (file-exists-p src-file))
+         nil 
+       (if just-print
+           (princ (format "%s -> %s\n" el-file dest))
+         (let ((full-path (expand-file-name el-file dest)))
+           (if (file-exists-p full-path)
+               (delete-file full-path))
+           (copy-file src-file full-path t t)
+           (princ (format "%s -> %s\n" el-file dest)))))
+      (setq src-file (expand-file-name elc-file src))
+      (if (not (file-exists-p src-file))
+         nil 
+       (if just-print
+           (princ (format "%s -> %s\n" elc-file dest))
+         (let ((full-path (expand-file-name elc-file dest)))
+            (if (file-exists-p full-path)
+                (delete-file full-path))
+           (copy-file src-file full-path t t)
+           (catch 'tag
+             (while (file-exists-p src-file)
+               (condition-case err
+                   (progn
+                     (delete-file src-file)
+                     (throw 'tag nil))
+                 (error (princ (format "%s\n" (nth 1 err)))))))
+           (princ (format "%s -> %s\n" elc-file dest))))))))
+
+(defun install-elisp-modules (modules src dest &optional just-print)
+  (or (file-exists-p dest)
+      (make-directory dest t))
+  (mapcar
+   (function
+    (lambda (module)
+      (install-elisp-module module src dest just-print)))
+   modules))
+
+
+;;; @ detect install path
+;;;
+
+;; install to shared directory (maybe "/usr/local")
+(defvar install-prefix
+  (if (or (<= emacs-major-version 18)
+         (featurep 'xemacs)
+         (and (boundp 'system-configuration-options) ; 19.29 or later
+              (string= system-configuration-options "NT"))) ; for Meadow
+      (expand-file-name "../../.." exec-directory)
+    (expand-file-name "../../../.." data-directory)))
+
+(defvar install-elisp-prefix
+  (if (>= emacs-major-version 19)
+      "site-lisp"
+    ;; v18 does not have standard site directory.
+    "local.lisp"))
+
+(defun install-detect-elisp-directory (&optional prefix elisp-prefix
+                                                allow-version-specific)
+  (or prefix
+      (setq prefix install-prefix))
+  (or elisp-prefix
+      (setq elisp-prefix install-elisp-prefix))
+  (or (catch 'tag
+       (let ((rest default-load-path)
+             (regexp (concat "^"
+                             (expand-file-name (concat ".*/" elisp-prefix)
+                                               prefix)
+                             "/?$")))
+         (while rest
+           (if (string-match regexp (car rest))
+               (if (or allow-version-specific
+                       (not (string-match (format "/%d\\.%d"
+                                                  emacs-major-version
+                                                  emacs-minor-version)
+                                          (car rest))))
+                   (throw 'tag (car rest))))
+           (setq rest (cdr rest)))))
+      (expand-file-name (concat (if (and (not (featurep 'xemacs))
+                                        (or (>= emacs-major-version 20)
+                                            (and (= emacs-major-version 19)
+                                                 (> emacs-minor-version 28))))
+                                   "share/"
+                                 "lib/")
+                               (cond
+                                ((featurep 'xemacs)
+                                 (if (featurep 'mule)
+                                     "xmule/"
+                                   "xemacs/"))
+                                ;; unfortunately, unofficial mule based on
+                                ;; 19.29 and later use "emacs/" by default.
+                                ((boundp 'MULE) "mule/")
+                                ((boundp 'NEMACS) "nemacs/")
+                                (t "emacs/"))
+                               elisp-prefix)
+                       prefix)))
+
+(defvar install-default-elisp-directory
+  (install-detect-elisp-directory))
+
+
+;;; @ end
+;;;
+
+(require 'product)
+(product-provide (provide 'install) (require 'apel-ver))
+
+;;; install.el ends here
diff --git a/emacs-lisp/path-util.el b/emacs-lisp/path-util.el
new file mode 100644 (file)
index 0000000..d774642
--- /dev/null
@@ -0,0 +1,203 @@
+;;; path-util.el --- Emacs Lisp file detection utility
+
+;; Copyright (C) 1996,1997,1999 Free Software Foundation, Inc.
+
+;; Author: MORIOKA Tomohiko <tomo@m17n.org>
+;; Keywords: file detection, install, module
+
+;; This file is part of APEL (A Portable Emacs Library).
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Code:
+
+(require 'poe)
+
+(defvar default-load-path load-path
+  "*Base of `load-path'.
+It is used as default value of target path to search file or
+subdirectory under load-path.")
+
+;;;###autoload
+(defun add-path (path &rest options)
+  "Add PATH to `load-path' if it exists under `default-load-path'
+directories and it does not exist in `load-path'.
+
+You can use following PATH styles:
+       load-path relative: \"PATH/\"
+                       (it is searched from `defaul-load-path')
+       home directory relative: \"~/PATH/\" \"~USER/PATH/\"
+       absolute path: \"/HOO/BAR/BAZ/\"
+
+You can specify following OPTIONS:
+       'all-paths      search from `load-path'
+                       instead of `default-load-path'
+       'append         add PATH to the last of `load-path'"
+  (let ((rest (if (memq 'all-paths options)
+                 load-path
+               default-load-path))
+       p)
+    (if (and (catch 'tag
+              (while rest
+                (setq p (expand-file-name path (car rest)))
+                (if (file-directory-p p)
+                    (throw 'tag p)
+                  )
+                (setq rest (cdr rest))
+                ))
+            (not (member p load-path))
+            )
+       (setq load-path
+             (if (memq 'append options)
+                 (append load-path (list p))
+               (cons p load-path)
+               ))
+      )))
+
+;;;###autoload
+(defun add-latest-path (pattern &optional all-paths)
+  "Add latest path matched by PATTERN to `load-path'
+if it exists under `default-load-path' directories
+and it does not exist in `load-path'.
+
+If optional argument ALL-PATHS is specified, it is searched from all
+of load-path instead of default-load-path."
+  (let ((path (get-latest-path pattern all-paths)))
+    (if path
+       (add-to-list 'load-path path)
+      )))
+
+;;;###autoload
+(defun get-latest-path (pattern &optional all-paths)
+  "Return latest directory in default-load-path
+which is matched to regexp PATTERN.
+If optional argument ALL-PATHS is specified,
+it is searched from all of load-path instead of default-load-path."
+  (catch 'tag
+    (let ((paths (if all-paths
+                   load-path
+                 default-load-path))
+         dir)
+      (while (setq dir (car paths))
+       (if (and (file-exists-p dir)
+                (file-directory-p dir)
+                )
+           (let ((files (sort (directory-files dir t pattern t)
+                              (function file-newer-than-file-p)))
+                 file)
+             (while (setq file (car files))
+               (if (file-directory-p file)
+                   (throw 'tag file)
+                 )
+               (setq files (cdr files))
+               )))
+       (setq paths (cdr paths))
+       ))))
+
+;;;###autoload
+(defun file-installed-p (file &optional paths)
+  "Return absolute-path of FILE if FILE exists in PATHS.
+If PATHS is omitted, `load-path' is used."
+  (if (null paths)
+      (setq paths load-path)
+    )
+  (catch 'tag
+    (let (path)
+      (while paths
+       (setq path (expand-file-name file (car paths)))
+       (if (file-exists-p path)
+           (throw 'tag path)
+         )
+       (setq paths (cdr paths))
+       ))))
+
+;;;###autoload
+(defvar exec-suffix-list '("")
+  "*List of suffixes for executable.")
+
+;;;###autoload
+(defun exec-installed-p (file &optional paths suffixes)
+  "Return absolute-path of FILE if FILE exists in PATHS.
+If PATHS is omitted, `exec-path' is used.
+If suffixes is omitted, `exec-suffix-list' is used."
+  (or paths
+      (setq paths exec-path)
+      )
+  (or suffixes
+      (setq suffixes exec-suffix-list)
+      )
+  (let (files)
+    (catch 'tag
+      (while suffixes
+       (let ((suf (car suffixes)))
+         (if (and (not (string= suf ""))
+                  (string-match (concat (regexp-quote suf) "$") file))
+             (progn
+               (setq files (list file))
+               (throw 'tag nil)
+               )
+           (setq files (cons (concat file suf) files))
+           )
+         (setq suffixes (cdr suffixes))
+         )))
+    (setq files (nreverse files))
+    (catch 'tag
+      (while paths
+       (let ((path (car paths))
+             (files files)
+             )
+         (while files
+           (setq file (expand-file-name (car files) path))
+           (if (file-executable-p file)
+               (throw 'tag file)
+             )
+           (setq files (cdr files))
+           )
+         (setq paths (cdr paths))
+         )))))
+
+;;;###autoload
+(defun module-installed-p (module &optional paths)
+  "Return t if module is provided or exists in PATHS.
+If PATHS is omitted, `load-path' is used."
+  (or (featurep module)
+      (let ((file (symbol-name module)))
+       (or paths
+           (setq paths load-path)
+           )
+       (catch 'tag
+         (while paths
+           (let ((stem (expand-file-name file (car paths)))
+                 (sufs '(".elc" ".el"))
+                 )
+             (while sufs
+               (let ((file (concat stem (car sufs))))
+                 (if (file-exists-p file)
+                     (throw 'tag file)
+                   ))
+               (setq sufs (cdr sufs))
+               ))
+           (setq paths (cdr paths))
+           )))))
+
+
+;;; @ end
+;;;
+
+(require 'product)
+(product-provide (provide 'path-util) (require 'apel-ver))
+
+;;; path-util.el ends here
diff --git a/mail/smtp.el b/mail/smtp.el
new file mode 100644 (file)
index 0000000..27a0b99
--- /dev/null
@@ -0,0 +1,412 @@
+;;; smtp.el --- basic functions to send mail with SMTP server
+
+;; Copyright (C) 1995, 1996, 1998, 1999 Free Software Foundation, Inc.
+
+;; Author: Tomoji Kagatani <kagatani@rbc.ncl.omron.co.jp>
+;;         Simon Leinen <simon@switch.ch> (ESMTP support)
+;;         Shuhei KOBAYASHI <shuhei@aqua.ocn.ne.jp>
+;; Keywords: SMTP, mail
+
+;; This file is part of FLIM (Faithful Library about Internet Message).
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Code:
+
+(require 'poe)
+(require 'poem)
+(require 'pcustom)
+(require 'mail-utils)                  ; mail-strip-quoted-names
+
+(eval-when-compile (require 'cl))      ; push
+
+(defgroup smtp nil
+  "SMTP protocol for sending mail."
+  :group 'mail)
+
+(defcustom smtp-default-server nil
+  "*Specify default SMTP server."
+  :type '(choice (const nil) string)
+  :group 'smtp)
+
+(defcustom smtp-server (or (getenv "SMTPSERVER") smtp-default-server)
+  "*The name of the host running SMTP server.  It can also be a function
+called from `smtp-via-smtp' with arguments SENDER and RECIPIENTS."
+  :type '(choice (string :tag "Name")
+                (function :tag "Function"))
+  :group 'smtp)
+
+(defcustom smtp-service "smtp"
+  "*SMTP service port number. \"smtp\" or 25."
+  :type '(choice (integer :tag "25" 25)
+                 (string :tag "smtp" "smtp"))
+  :group 'smtp)
+
+(defcustom smtp-use-8bitmime t
+  "*If non-nil, use ESMTP 8BITMIME if available."
+  :type 'boolean
+  :group 'smtp)
+
+(defcustom smtp-local-domain nil
+  "*Local domain name without a host name.
+If the function (system-name) returns the full internet address,
+don't define this value."
+  :type '(choice (const nil) string)
+  :group 'smtp)
+
+(defcustom smtp-debug-info nil
+  "*smtp debug info printout. messages and process buffer."
+  :type 'boolean
+  :group 'smtp)
+
+(defcustom smtp-notify-success nil
+  "*If non-nil, notification for successful mail delivery is returned 
+ to user (RFC1891)."
+  :type 'boolean
+  :group 'smtp)
+(defvar smtp-read-point nil)
+
+(defun smtp-make-fqdn ()
+  "Return user's fully qualified domain name."
+  (let ((system-name (system-name)))
+    (cond
+     (smtp-local-domain
+      (concat system-name "." smtp-local-domain))
+     ((string-match "[^.]\\.[^.]" system-name)
+      system-name)
+     (t
+      (error "Cannot generate valid FQDN. Set `smtp-local-domain' correctly.")))))
+
+(defun smtp-via-smtp (sender recipients smtp-text-buffer)
+  (let ((server (if (functionp smtp-server)
+                   (funcall smtp-server sender recipients)
+                 smtp-server))
+       process response extensions)
+    (save-excursion
+      (set-buffer
+       (get-buffer-create
+       (format "*trace of SMTP session to %s*" server)))
+      (erase-buffer)
+      (make-local-variable 'smtp-read-point)
+      (setq smtp-read-point (point-min))
+
+      (unwind-protect
+         (catch 'done
+           (setq process (open-network-stream-as-binary
+                          "SMTP" (current-buffer) server smtp-service))
+           (or process (throw 'done nil))
+
+           (set-process-filter process 'smtp-process-filter)
+
+           ;; Greeting
+           (setq response (smtp-read-response process))
+           (if (or (null (car response))
+                   (not (integerp (car response)))
+                   (>= (car response) 400))
+               (throw 'done (car (cdr response))))
+
+           ;; EHLO
+           (smtp-send-command process
+                              (format "EHLO %s" (smtp-make-fqdn)))
+           (setq response (smtp-read-response process))
+           (if (or (null (car response))
+                   (not (integerp (car response)))
+                   (>= (car response) 400))
+               (progn
+                 ;; HELO
+                 (smtp-send-command process
+                                    (format "HELO %s" (smtp-make-fqdn)))
+                 (setq response (smtp-read-response process))
+                 (if (or (null (car response))
+                         (not (integerp (car response)))
+                         (>= (car response) 400))
+                     (throw 'done (car (cdr response)))))
+             (let ((extension-lines (cdr (cdr response))))
+               (while extension-lines
+                 (push (intern (downcase (substring (car extension-lines) 4)))
+                       extensions)
+                 (setq extension-lines (cdr extension-lines)))))
+
+           ;; ONEX --- One message transaction only (sendmail extension?)
+           (if (or (memq 'onex extensions)
+                   (memq 'xone extensions))
+               (progn
+                 (smtp-send-command process "ONEX")
+                 (setq response (smtp-read-response process))
+                 (if (or (null (car response))
+                         (not (integerp (car response)))
+                         (>= (car response) 400))
+                     (throw 'done (car (cdr response))))))
+
+           ;; VERB --- Verbose (sendmail extension?)
+           (if (and smtp-debug-info
+                    (or (memq 'verb extensions)
+                        (memq 'xvrb extensions)))
+               (progn
+                 (smtp-send-command process "VERB")
+                 (setq response (smtp-read-response process))
+                 (if (or (null (car response))
+                         (not (integerp (car response)))
+                         (>= (car response) 400))
+                     (throw 'done (car (cdr response))))))
+
+           ;; XUSR --- Initial (user) submission (sendmail extension?)
+           (if (memq 'xusr extensions)
+               (progn
+                 (smtp-send-command process "XUSR")
+                 (setq response (smtp-read-response process))
+                 (if (or (null (car response))
+                         (not (integerp (car response)))
+                         (>= (car response) 400))
+                     (throw 'done (car (cdr response))))))
+
+           ;; MAIL FROM:<sender>
+           (smtp-send-command
+            process
+            (format "MAIL FROM:<%s>%s%s"
+                    sender
+                    ;; SIZE --- Message Size Declaration (RFC1870)
+                    (if (memq 'size extensions)
+                        (format " SIZE=%d"
+                                (save-excursion
+                                  (set-buffer smtp-text-buffer)
+                                  (+ (- (point-max) (point-min))
+                                     ;; Add one byte for each change-of-line
+                                     ;; because or CR-LF representation:
+                                     (count-lines (point-min) (point-max))
+                                     ;; For some reason, an empty line is
+                                     ;; added to the message.  Maybe this
+                                     ;; is a bug, but it can't hurt to add
+                                     ;; those two bytes anyway:
+                                     2)))
+                      "")
+                    ;; 8BITMIME --- 8bit-MIMEtransport (RFC1652)
+                    (if (and (memq '8bitmime extensions)
+                             smtp-use-8bitmime)
+                        " BODY=8BITMIME"
+                      "")))
+           (setq response (smtp-read-response process))
+           (if (or (null (car response))
+                   (not (integerp (car response)))
+                   (>= (car response) 400))
+               (throw 'done (car (cdr response))))
+
+           ;; RCPT TO:<recipient>
+           (while recipients
+             (smtp-send-command process
+                                (format
+                                 (if smtp-notify-success
+                                     "RCPT TO:<%s> NOTIFY=SUCCESS" 
+                                   "RCPT TO:<%s>")
+                                 (car recipients)))
+             (setq recipients (cdr recipients))
+             (setq response (smtp-read-response process))
+             (if (or (null (car response))
+                     (not (integerp (car response)))
+                     (>= (car response) 400))
+                 (throw 'done (car (cdr response)))))
+
+           ;; DATA
+           (smtp-send-command process "DATA")
+           (setq response (smtp-read-response process))
+           (if (or (null (car response))
+                   (not (integerp (car response)))
+                   (>= (car response) 400))
+               (throw 'done (car (cdr response))))
+
+           ;; Mail contents
+           (smtp-send-data process smtp-text-buffer)
+
+           ;; DATA end "."
+           (smtp-send-command process ".")
+           (setq response (smtp-read-response process))
+           (if (or (null (car response))
+                   (not (integerp (car response)))
+                   (>= (car response) 400))
+               (throw 'done (car (cdr response))))
+
+           t)
+
+       (if (and process
+                (eq (process-status process) 'open))
+           (progn
+             ;; QUIT
+             (smtp-send-command process "QUIT")
+             (smtp-read-response process)
+             (delete-process process)))))))
+
+(defun smtp-process-filter (process output)
+  (save-excursion
+    (set-buffer (process-buffer process))
+    (goto-char (point-max))
+    (insert output)))
+
+(defun smtp-read-response (process)
+  (let ((case-fold-search nil)
+       (response-strings nil)
+       (response-continue t)
+       (return-value '(nil ()))
+       match-end)
+
+    (while response-continue
+      (goto-char smtp-read-point)
+      (while (not (search-forward "\r\n" nil t))
+       (accept-process-output process)
+       (goto-char smtp-read-point))
+
+      (setq match-end (point))
+      (setq response-strings
+           (cons (buffer-substring smtp-read-point (- match-end 2))
+                 response-strings))
+       
+      (goto-char smtp-read-point)
+      (if (looking-at "[0-9]+ ")
+         (let ((begin (match-beginning 0))
+               (end (match-end 0)))
+           (if smtp-debug-info
+               (message "%s" (car response-strings)))
+
+           (setq smtp-read-point match-end)
+
+           ;; ignore lines that start with "0"
+           (if (looking-at "0[0-9]+ ")
+               nil
+             (setq response-continue nil)
+             (setq return-value
+                   (cons (string-to-int
+                          (buffer-substring begin end))
+                         (nreverse response-strings)))))
+       
+       (if (looking-at "[0-9]+-")
+           (progn (if smtp-debug-info
+                    (message "%s" (car response-strings)))
+                  (setq smtp-read-point match-end)
+                  (setq response-continue t))
+         (progn
+           (setq smtp-read-point match-end)
+           (setq response-continue nil)
+           (setq return-value
+                 (cons nil (nreverse response-strings)))))))
+    (setq smtp-read-point match-end)
+    return-value))
+
+(defun smtp-send-command (process command)
+  (goto-char (point-max))
+  (insert command "\r\n")
+  (setq smtp-read-point (point))
+  (process-send-string process command)
+  (process-send-string process "\r\n"))
+
+(defun smtp-send-data-1 (process data)
+  (goto-char (point-max))
+  (if smtp-debug-info
+      (insert data "\r\n"))
+  (setq smtp-read-point (point))
+  ;; Escape "." at start of a line.
+  (if (eq (string-to-char data) ?.)
+      (process-send-string process "."))
+  (process-send-string process data)
+  (process-send-string process "\r\n"))
+
+(defun smtp-send-data (process buffer)
+  (let ((data-continue t)
+       (sending-data nil)
+       this-line
+       this-line-end)
+
+    (save-excursion
+      (set-buffer buffer)
+      (goto-char (point-min)))
+
+    (while data-continue
+      (save-excursion
+       (set-buffer buffer)
+       (beginning-of-line)
+       (setq this-line (point))
+       (end-of-line)
+       (setq this-line-end (point))
+       (setq sending-data nil)
+       (setq sending-data (buffer-substring this-line this-line-end))
+       (if (or (/= (forward-line 1) 0) (eobp))
+           (setq data-continue nil)))
+
+      (smtp-send-data-1 process sending-data))))
+
+(defun smtp-deduce-address-list (smtp-text-buffer header-start header-end)
+  "Get address list suitable for smtp RCPT TO:<address>."
+  (let ((simple-address-list "")
+       this-line
+       this-line-end
+       addr-regexp
+       (smtp-address-buffer (generate-new-buffer " *smtp-mail*")))
+    (unwind-protect
+       (save-excursion
+         ;;
+         (set-buffer smtp-address-buffer)
+         (setq case-fold-search t)
+         (erase-buffer)
+         (insert (save-excursion
+                   (set-buffer smtp-text-buffer)
+                   (buffer-substring-no-properties header-start header-end)))
+         (goto-char (point-min))
+         ;; RESENT-* fields should stop processing of regular fields.
+         (save-excursion
+           (if (re-search-forward "^RESENT-TO:" header-end t)
+               (setq addr-regexp
+                     "^\\(RESENT-TO:\\|RESENT-CC:\\|RESENT-BCC:\\)")
+             (setq addr-regexp  "^\\(TO:\\|CC:\\|BCC:\\)")))
+
+         (while (re-search-forward addr-regexp header-end t)
+           (replace-match "")
+           (setq this-line (match-beginning 0))
+           (forward-line 1)
+           ;; get any continuation lines.
+           (while (and (looking-at "^[ \t]+") (< (point) header-end))
+             (forward-line 1))
+           (setq this-line-end (point-marker))
+           (setq simple-address-list
+                 (concat simple-address-list " "
+                         (mail-strip-quoted-names
+                          (buffer-substring this-line this-line-end)))))
+         (erase-buffer)
+         (insert-string " ")
+         (insert-string simple-address-list)
+         (insert-string "\n")
+         ;; newline --> blank
+         (subst-char-in-region (point-min) (point-max) 10 ?  t)
+         ;; comma   --> blank
+         (subst-char-in-region (point-min) (point-max) ?, ?  t)
+         ;; tab     --> blank
+         (subst-char-in-region (point-min) (point-max)  9 ?  t)
+
+         (goto-char (point-min))
+         ;; tidyness in case hook is not robust when it looks at this
+         (while (re-search-forward "[ \t]+" header-end t) (replace-match " "))
+
+         (goto-char (point-min))
+         (let (recipient-address-list)
+           (while (re-search-forward " \\([^ ]+\\) " (point-max) t)
+             (backward-char 1)
+             (setq recipient-address-list
+                   (cons (buffer-substring (match-beginning 1) (match-end 1))
+                         recipient-address-list)))
+           recipient-address-list))
+      (kill-buffer smtp-address-buffer))))
+
+(provide 'smtp)
+
+;;; smtp.el ends here
diff --git a/richtext.el b/richtext.el
new file mode 100644 (file)
index 0000000..8b1718c
--- /dev/null
@@ -0,0 +1,185 @@
+;;; richtext.el -- read and save files in text/richtext format
+
+;; Copyright (C) 1995,1996,1997 Free Software Foundation, Inc.
+
+;; Author: MORIOKA Tomohiko <morioka@jaist.ac.jp>
+;; Created: 1995/7/15
+;; Version: $Id: richtext.el,v 1.1.2.1 2000/02/03 05:01:36 tomo Exp $
+;; Keywords: wp, faces, MIME, multimedia
+
+;; This file is not part of GNU Emacs yet.
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Code:
+
+(require 'enriched)
+
+
+;;; @ variables
+;;;
+
+(defconst richtext-initial-annotation
+  (lambda ()
+    (format "Content-Type: text/richtext\nText-Width: %d\n\n"
+           (enriched-text-width)))
+  "What to insert at the start of a text/richtext file.
+If this is a string, it is inserted.  If it is a list, it should be a lambda
+expression, which is evaluated to get the string to insert.")
+
+(defconst richtext-annotation-regexp
+  "[ \t\n]*\\(<\\(/\\)?\\([-A-za-z0-9]+\\)>\\)[ \t\n]*"
+  "Regular expression matching richtext annotations.")
+
+(defconst richtext-translations
+  '((face          (bold-italic "bold" "italic")
+                  (bold        "bold")
+                  (italic      "italic")
+                  (underline   "underline")
+                  (fixed       "fixed")
+                  (excerpt     "excerpt")
+                  (default     )
+                  (nil         enriched-encode-other-face))
+    (invisible     (t           "comment"))
+    (left-margin   (4           "indent"))
+    (right-margin  (4           "indentright"))
+    (justification (right       "flushright")
+                  (left        "flushleft")
+                  (full        "flushboth")
+                  (center      "center")) 
+    ;; The following are not part of the standard:
+    (FUNCTION      (enriched-decode-foreground "x-color")
+                  (enriched-decode-background "x-bg-color"))
+    (read-only     (t           "x-read-only"))
+    (unknown       (nil         format-annotate-value))
+;   (font-size     (2           "bigger")       ; unimplemented
+;                 (-2          "smaller"))
+)
+  "List of definitions of text/richtext annotations.
+See `format-annotate-region' and `format-deannotate-region' for the definition
+of this structure.")
+
+
+;;; @ encoder
+;;;
+
+;;;###autoload
+(defun richtext-encode (from to)
+  (if enriched-verbose (message "Richtext: encoding document..."))
+  (save-restriction
+    (narrow-to-region from to)
+    (delete-to-left-margin)
+    (unjustify-region)
+    (goto-char from)
+    (format-replace-strings '(("<" . "<lt>")))
+    (format-insert-annotations 
+     (format-annotate-region from (point-max) richtext-translations
+                            'enriched-make-annotation enriched-ignore))
+    (goto-char from)
+    (insert (if (stringp enriched-initial-annotation)
+               richtext-initial-annotation
+             (funcall richtext-initial-annotation)))
+    (enriched-map-property-regions 'hard
+      (lambda (v b e)
+       (goto-char b)
+       (if (eolp)
+           (while (search-forward "\n" nil t)
+             (replace-match "<nl>\n")
+             )))
+      (point) nil)
+    (if enriched-verbose (message nil))
+    ;; Return new end.
+    (point-max)))
+
+
+;;; @ decoder
+;;;
+
+(defun richtext-next-annotation ()
+  "Find and return next text/richtext annotation.
+Return value is \(begin end name positive-p), or nil if none was found."
+  (catch 'tag
+    (while (re-search-forward richtext-annotation-regexp nil t)
+      (let* ((beg0 (match-beginning 0))
+            (end0 (match-end 0))
+            (beg  (match-beginning 1))
+            (end  (match-end 1))
+            (name (downcase (buffer-substring 
+                             (match-beginning 3) (match-end 3))))
+            (pos (not (match-beginning 2)))
+            )
+       (cond ((equal name "lt")
+              (delete-region beg end)
+              (goto-char beg)
+              (insert "<")
+              )
+             ((equal name "comment")
+              (if pos
+                  (throw 'tag (list beg0 end name pos))
+                (throw 'tag (list beg end0 name pos))
+                )
+              )
+             (t
+              (throw 'tag (list beg end name pos))
+              ))
+       ))))
+
+;;;###autoload
+(defun richtext-decode (from to)
+  (if enriched-verbose (message "Richtext: decoding document..."))
+  (save-excursion
+    (save-restriction
+      (narrow-to-region from to)
+      (goto-char from)
+      (let ((file-width (enriched-get-file-width))
+           (use-hard-newlines t))
+       (enriched-remove-header)
+       
+       (goto-char from)
+       (while (re-search-forward "\n\n+" nil t)
+         (replace-match "\n")
+         )
+       
+       ;; Deal with newlines
+       (goto-char from)
+       (while (re-search-forward "[ \t\n]*<nl>[ \t\n]*" nil t)
+         (replace-match "\n")
+         (put-text-property (match-beginning 0) (point) 'hard t)
+         (put-text-property (match-beginning 0) (point) 'front-sticky nil)
+         )
+       
+       ;; Translate annotations
+       (format-deannotate-region from (point-max) richtext-translations
+                                 'richtext-next-annotation)
+
+       ;; Fill paragraphs
+       (if (and file-width             ; possible reasons not to fill:
+                (= file-width (enriched-text-width))) ; correct wd.
+           ;; Minimally, we have to insert indentation and justification.
+           (enriched-insert-indentation)
+         (if enriched-verbose (message "Filling paragraphs..."))
+         (fill-region (point-min) (point-max))))
+      (if enriched-verbose (message nil))
+      (point-max))))
+
+
+;;; @ end
+;;;
+
+(require 'product)
+(product-provide (provide 'richtext) (require 'apel-ver))
+
+;;; richtext.el ends here