(insert-entity-content): New method.
[elisp/flim.git] / std11.el
index 56b133c..fd7133f 100644 (file)
--- a/std11.el
+++ b/std11.el
@@ -27,6 +27,8 @@
 (or (fboundp 'buffer-substring-no-properties)
     (require 'poe))
 
+(require 'custom)
+
 
 ;;; @ fetch
 ;;;
@@ -48,6 +50,7 @@
   (point)
   )
 
+;;;###autoload
 (defun std11-fetch-field (name)
   "Return the value of the header field NAME.
 The buffer is expected to be narrowed to just the headers of the message."
@@ -58,6 +61,7 @@ The buffer is expected to be narrowed to just the headers of the message."
          (buffer-substring-no-properties (match-end 0) (std11-field-end))
        ))))
 
+;;;###autoload
 (defun std11-narrow-to-header (&optional boundary)
   "Narrow to the message header.
 If BOUNDARY is not nil, it is used as message header separator."
@@ -70,6 +74,7 @@ If BOUNDARY is not nil, it is used as message header separator."
      (point-max)
      )))
 
+;;;###autoload
 (defun std11-field-body (name &optional boundary)
   "Return the value of the header field NAME.
 If BOUNDARY is not nil, it is used as message header separator."
@@ -125,8 +130,7 @@ header separator."
 
 (defun std11-header-string (regexp &optional boundary)
   "Return string of message header fields matched by REGEXP.
-If BOUNDARY is not nil, it is used as message header separator.
-\[std11.el]"
+If BOUNDARY is not nil, it is used as message header separator."
   (let ((case-fold-search t))
     (save-excursion
       (save-restriction
@@ -144,8 +148,7 @@ If BOUNDARY is not nil, it is used as message header separator.
 
 (defun std11-header-string-except (regexp &optional boundary)
   "Return string of message header fields not matched by REGEXP.
-If BOUNDARY is not nil, it is used as message header separator.
-\[std11.el]"
+If BOUNDARY is not nil, it is used as message header separator."
   (let ((case-fold-search t))
     (save-excursion
       (save-restriction
@@ -163,8 +166,7 @@ If BOUNDARY is not nil, it is used as message header separator.
 
 (defun std11-collect-field-names (&optional boundary)
   "Return list of all field-names of the message header in current buffer.
-If BOUNDARY is not nil, it is used as message header separator.
-\[std11.el]"
+If BOUNDARY is not nil, it is used as message header separator."
   (save-excursion
     (save-restriction
       (std11-narrow-to-header boundary)
@@ -183,6 +185,7 @@ If BOUNDARY is not nil, it is used as message header separator.
 ;;; @ unfolding
 ;;;
 
+;;;###autoload
 (defun std11-unfold-string (string)
   "Unfold STRING as message header field."
   (let ((dest "")
@@ -222,13 +225,13 @@ If BOUNDARY is not nil, it is used as message header separator.
 (defconst std11-non-qtext-char-list '(?\" ?\\ ?\r ?\n))
 
 (defun std11-wrap-as-quoted-string (string)
-  "Wrap STRING as RFC 822 quoted-string. [std11.el]"
+  "Wrap STRING as RFC 822 quoted-string."
   (concat "\""
          (std11-wrap-as-quoted-pairs string std11-non-qtext-char-list)
          "\""))
 
 (defun std11-strip-quoted-pair (string)
-  "Strip quoted-pairs in STRING. [std11.el]"
+  "Strip quoted-pairs in STRING."
   (let (dest
        (b 0)
        (i 0)
@@ -246,7 +249,7 @@ If BOUNDARY is not nil, it is used as message header separator.
     ))
 
 (defun std11-strip-quoted-string (string)
-  "Strip quoted-string STRING. [std11.el]"
+  "Strip quoted-string STRING."
   (let ((len (length string)))
     (or (and (>= len 2)
             (let ((max (1- len)))
@@ -260,54 +263,77 @@ If BOUNDARY is not nil, it is used as message header separator.
 ;;; @ lexical analyze
 ;;;
 
+(defcustom std11-lexical-analyzer
+  '(std11-analyze-quoted-string
+    std11-analyze-domain-literal
+    std11-analyze-comment
+    std11-analyze-spaces
+    std11-analyze-special
+    std11-analyze-atom)
+  "*List of functions to return result of lexical analyze.
+Each function must have two arguments: STRING and START.
+STRING is the target string to be analyzed.
+START is start position of STRING to analyze.
+
+Previous function is preferred to next function.  If a function
+returns nil, next function is used.  Otherwise the return value will
+be the result."
+  :group 'news
+  :group 'mail
+  :type '(repeat function))
+
 (eval-and-compile
-  (defconst std11-space-chars " \t\n")
+  (defconst std11-space-char-list '(?  ?\t ?\n))
   (defconst std11-special-char-list '(?\] ?\[
                                          ?\( ?\) ?< ?> ?@
                                          ?, ?\; ?: ?\\ ?\"
                                          ?.))
   )
 ;; (defconst std11-spaces-regexp
-;;   (eval-when-compile (concat "[" std11-space-chars "]+")))
+;;   (eval-when-compile (concat "[" std11-space-char-list "]+")))
 (defconst std11-atom-regexp
   (eval-when-compile
-    (concat "^[^" std11-special-char-list std11-space-chars "]+")))
+    (concat "[^" std11-special-char-list std11-space-char-list "]+")))
 
-(defun std11-analyze-spaces (string)
-  (if (and (string-match
-           (eval-when-compile (concat "[" std11-space-chars "]+"))
-           string)
-          (= (match-beginning 0) 0))
+(defun std11-analyze-spaces (string start)
+  (if (and (string-match (eval-when-compile
+                          (concat "[" std11-space-char-list "]+"))
+                        string start)
+          (= (match-beginning 0) start))
       (let ((end (match-end 0)))
-       (cons (cons 'spaces (substring string 0 end))
-             (substring string end)
-             ))))
-
-(defun std11-analyze-special (str)
-  (if (and (> (length str) 0)
-          (memq (aref str 0) std11-special-char-list))
-      (cons (cons 'specials (substring str 0 1))
-           (substring str 1)
-           )))
-
-(defun std11-analyze-atom (str)
-  (if (string-match std11-atom-regexp str)
+       (cons (cons 'spaces (substring string start end))
+             ;;(substring string end)
+             end)
+       )))
+
+(defun std11-analyze-special (string start)
+  (if (and (> (length string) start)
+          (memq (aref string start) std11-special-char-list))
+      (cons (cons 'specials (substring string start (1+ start)))
+           ;;(substring string 1)
+           (1+ start))
+    ))
+
+(defun std11-analyze-atom (string start)
+  (if (and (string-match std11-atom-regexp string start)
+          (= (match-beginning 0) start))
       (let ((end (match-end 0)))
-       (cons (cons 'atom (substring str 0 end))
-             (substring str end)
-             ))))
+       (cons (cons 'atom (substring string start end))
+             ;;(substring string end)
+             end)
+       )))
 
-(defun std11-check-enclosure (str open close &optional recursive from)
-  (let ((len (length str))
+(defun std11-check-enclosure (string open close &optional recursive from)
+  (let ((len (length string))
        (i (or from 0))
        )
     (if (and (> len i)
-            (eq (aref str i) open))
+            (eq (aref string i) open))
        (let (p chr)
          (setq i (1+ i))
          (catch 'tag
            (while (< i len)
-             (setq chr (aref str i))
+             (setq chr (aref string i))
              (cond ((eq chr ?\\)
                     (setq i (1+ i))
                     (if (>= i len)
@@ -321,7 +347,7 @@ If BOUNDARY is not nil, it is used as message header separator.
                    ((eq chr open)
                     (if (and recursive
                              (setq p (std11-check-enclosure
-                                      str open close recursive i))
+                                      string open close recursive i))
                              )
                         (setq i p)
                       (throw 'tag nil)
@@ -331,41 +357,51 @@ If BOUNDARY is not nil, it is used as message header separator.
                     ))
              ))))))
 
-(defun std11-analyze-quoted-string (str)
-  (let ((p (std11-check-enclosure str ?\" ?\")))
+(defun std11-analyze-quoted-string (string start)
+  (let ((p (std11-check-enclosure string ?\" ?\" nil start)))
     (if p
-       (cons (cons 'quoted-string (substring str 1 (1- p)))
-             (substring str p))
+       (cons (cons 'quoted-string (substring string (1+ start) (1- p)))
+             ;;(substring string p))
+             p)
       )))
 
-(defun std11-analyze-domain-literal (str)
-  (let ((p (std11-check-enclosure str ?\[ ?\])))
+(defun std11-analyze-domain-literal (string start)
+  (let ((p (std11-check-enclosure string ?\[ ?\] nil start)))
     (if p
-       (cons (cons 'domain-literal (substring str 1 (1- p)))
-             (substring str p))
+       (cons (cons 'domain-literal (substring string (1+ start) (1- p)))
+             ;;(substring string p))
+             p)
       )))
 
-(defun std11-analyze-comment (str)
-  (let ((p (std11-check-enclosure str ?\( ?\) t)))
+(defun std11-analyze-comment (string start)
+  (let ((p (std11-check-enclosure string ?\( ?\) t start)))
     (if p
-       (cons (cons 'comment (substring str 1 (1- p)))
-             (substring str p))
+       (cons (cons 'comment (substring string (1+ start) (1- p)))
+             ;;(substring string p))
+             p)
       )))
 
-(defun std11-lexical-analyze (str)
-  (let (dest ret)
-    (while (not (string-equal str ""))
+;;;###autoload
+(defun std11-lexical-analyze (string &optional analyzer start)
+  "Analyze STRING as lexical tokens of STD 11."
+  (or analyzer
+      (setq analyzer std11-lexical-analyzer))
+  (or start
+      (setq start 0))
+  (let ((len (length string))
+       dest ret)
+    (while (< start len)
       (setq ret
-           (or (std11-analyze-quoted-string str)
-               (std11-analyze-domain-literal str)
-               (std11-analyze-comment str)
-               (std11-analyze-spaces str)
-               (std11-analyze-special str)
-               (std11-analyze-atom str)
-               '((error) . "")
-               ))
-      (setq dest (cons (car ret) dest))
-      (setq str (cdr ret))
+           (let ((rest analyzer)
+                 func r)
+             (while (and (setq func (car rest))
+                         (null (setq r (funcall func string start))))
+               (setq rest (cdr rest)))
+             (or r
+                 (list (cons 'error (substring string start)) (1+ len)))
+             ))
+      (setq dest (cons (car ret) dest)
+           start (cdr ret))
       )
     (nreverse dest)
     ))
@@ -686,8 +722,8 @@ If BOUNDARY is not nil, it is used as message header separator.
              (cdr ret))
       )))
 
-(defun std11-parse-in-reply-to (tokens)
-  "Parse lexical TOKENS as In-Reply-To field, and return the result."
+(defun std11-parse-msg-ids (tokens)
+  "Parse lexical TOKENS as `*(phrase / msg-id)', and return the result."
   (let ((ret (or (std11-parse-msg-id tokens)
                 (std11-parse-phrase tokens))))
     (if ret
@@ -701,13 +737,16 @@ If BOUNDARY is not nil, it is used as message header separator.
          (nreverse dest)
          ))))
 
+(defalias 'std11-parse-in-reply-to 'std11-parse-msg-ids)
+(make-obsolete 'std11-parse-in-reply-to 'std11-parse-msg-ids)
+
 
 ;;; @ composer
 ;;;
 
 (defun std11-addr-to-string (seq)
   "Return string from lexical analyzed list SEQ
-represents addr-spec of RFC 822. [std11.el]"
+represents addr-spec of RFC 822."
   (mapconcat (function
              (lambda (token)
                (let ((name (car token)))
@@ -721,9 +760,9 @@ represents addr-spec of RFC 822. [std11.el]"
             seq "")
   )
 
+;;;###autoload
 (defun std11-address-string (address)
-  "Return string of address part from parsed ADDRESS of RFC 822.
-\[std11.el]"
+  "Return string of address part from parsed ADDRESS of RFC 822."
   (cond ((eq (car address) 'group)
         (mapconcat (function std11-address-string)
                    (car (cdr address))
@@ -756,6 +795,7 @@ represents addr-spec of RFC 822. [std11.el]"
        )
       dest)))
 
+;;;###autoload
 (defun std11-full-name-string (address)
   "Return string of full-name part from parsed ADDRESS of RFC 822."
   (cond ((eq (car address) 'group)
@@ -794,11 +834,13 @@ represents addr-spec of RFC 822. [std11.el]"
                 )
           ))))
 
+;;;###autoload
 (defun std11-msg-id-string (msg-id)
   "Return string from parsed MSG-ID of RFC 822."
   (concat "<" (std11-addr-to-string (cdr msg-id)) ">")
   )
 
+;;;###autoload
 (defun std11-fill-msg-id-list-string (string &optional column)
   "Fill list of msg-id in STRING, and return the result."
   (or column
@@ -840,20 +882,35 @@ represents addr-spec of RFC 822. [std11.el]"
 ;;; @ parser with lexical analyzer
 ;;;
 
+;;;###autoload
 (defun std11-parse-address-string (string)
-  "Parse STRING as mail address. [std11.el]"
+  "Parse STRING as mail address."
   (std11-parse-address (std11-lexical-analyze string))
   )
 
+;;;###autoload
 (defun std11-parse-addresses-string (string)
-  "Parse STRING as mail address list. [std11.el]"
+  "Parse STRING as mail address list."
   (std11-parse-addresses (std11-lexical-analyze string))
   )
 
+;;;###autoload
+(defun std11-parse-msg-id-string (string)
+  "Parse STRING as msg-id."
+  (std11-parse-msg-id (std11-lexical-analyze string))
+  )
+
+;;;###autoload
+(defun std11-parse-msg-ids-string (string)
+  "Parse STRING as `*(phrase / msg-id)'."
+  (std11-parse-msg-ids (std11-lexical-analyze string))
+  )
+
+;;;###autoload
 (defun std11-extract-address-components (string)
   "Extract full name and canonical address from STRING.
 Returns a list of the form (FULL-NAME CANONICAL-ADDRESS).
-If no name can be extracted, FULL-NAME will be nil. [std11.el]"
+If no name can be extracted, FULL-NAME will be nil."
   (let* ((structure (car (std11-parse-address-string
                          (std11-unfold-string string))))
          (phrase  (std11-full-name-string structure))