]> code.delx.au - gnu-emacs/blobdiff - lisp/nxml/xmltok.el
Merge from origin/emacs-24
[gnu-emacs] / lisp / nxml / xmltok.el
index add55bf9840e13696a725870ec0b9dc47c79b269..fe6a6050be9fe466259e1c23a71ad774125cec1f 100644 (file)
@@ -1,16 +1,16 @@
-;;; xmltok.el --- XML tokenization
+;;; xmltok.el --- XML tokenization  -*- lexical-binding:t -*-
 
-;; Copyright (C) 2003, 2007 Free Software Foundation, Inc.
+;; Copyright (C) 2003, 2007-2015 Free Software Foundation, Inc.
 
 ;; Author: James Clark
-;; Keywords: XML
+;; Keywords: wp, hypermedia, languages, XML
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs 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 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -18,9 +18,7 @@
 ;; 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., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
@@ -119,8 +117,8 @@ first member of the alist is t if references to entities not in the
 alist are well-formed \(e.g. because there's an external subset that
 wasn't parsed).
 
-Each general entity name is a string. The definition is either nil, a
-symbol, a string, a cons cell.  If the definition is nil, then it
+Each general entity name is a string.  The definition is either nil,
+symbol, a string, a cons cell.  If the definition is nil, then it
 means that it's an internal entity but the result of parsing it is
 unknown.  If it is a symbol, then the symbol is either `unparsed',
 meaning the entity is an unparsed entity, `external', meaning the
@@ -128,39 +126,12 @@ entity is or references an external entity, `element', meaning the
 entity includes one or more elements, or `not-well-formed', meaning
 the replacement text is not well-formed.  If the definition is a
 string, then the replacement text of the entity is that string; this
-happens only during the parsing of the prolog. If the definition is a
-cons cell \(ER . AR), then ER specifies the string that results from
-referencing the entity in element content and AR is either nil,
+happens only during the parsing of the prolog.  If the definition is
+a cons cell \(ER . AR), then ER specifies the string that results
+from referencing the entity in element content and AR is either nil,
 meaning the replacement text included a <, or a string which is the
 normalized attribute value.")
 
-(defvar xmltok-dependent-regions nil
-  "List of descriptors of regions that a parsed token depends on.
-
-A token depends on a region if the region occurs after the token and a
-change in the region may require the token to be reparsed.  This only
-happens with markup that is not well-formed.  For example, if a <?
-occurs without a matching ?>, then the <? is returned as a
-not-well-formed token.  However, this token is dependent on region
-from the end of the token to the end of the buffer: if this ever
-contains ?> then the buffer must be reparsed from the <?.
-
-A region descriptor is a list (FUN START END ARG ...), where FUN is a
-function to be called when the region changes, START and END are
-integers giving the start and end of the region, and ARG... are
-additional arguments to be passed to FUN.  FUN will be called with 5
-arguments followed by the additional arguments if any: the position of
-the start of the changed area in the region, the position of the end
-of the changed area in the region, the length of the changed area
-before the change, the position of the start of the region, the
-position of the end of the region. FUN must return non-nil if the
-region needs reparsing.  FUN will be called in a save-excursion with
-match-data saved.
-
-`xmltok-forward', `xmltok-forward-special' and `xmltok-forward-prolog'
-may add entries to the beginning of this list, but will not clear it.
-`xmltok-forward' and `xmltok-forward-special' will only add entries
-when returning tokens of type not-well-formed.")
 
 (defvar xmltok-errors nil
   "List of errors detected by `xmltok-forward' and `xmltok-forward-prolog'.
@@ -171,6 +142,7 @@ string giving the error message and START and END are integers
 indicating the position of the error.")
 
 (defmacro xmltok-save (&rest body)
+  (declare (indent 0) (debug t))
   `(let (xmltok-type
         xmltok-start
         xmltok-name-colon
@@ -178,13 +150,9 @@ indicating the position of the error.")
         xmltok-replacement
         xmltok-attributes
         xmltok-namespace-attributes
-        xmltok-dependent-regions
         xmltok-errors)
      ,@body))
 
-(put 'xmltok-save 'lisp-indent-function 0)
-(def-edebug-spec xmltok-save t)
-
 (defsubst xmltok-attribute-name-start (att)
   (aref att 0))
 
@@ -202,16 +170,16 @@ indicating the position of the error.")
 
 (defsubst xmltok-attribute-raw-normalized-value (att)
   "Return an object representing the normalized value of ATT.
-This can t indicating that the normalized value is the same as the
-buffer substring from the start to the end of the value or nil
+This can be t indicating that the normalized value is the same as
+the buffer substring from the start to the end of the value, or nil
 indicating that the value is not well-formed or a string."
   (aref att 5))
 
 (defsubst xmltok-attribute-refs (att)
   "Return a list of the entity and character references in ATT.
 Each member is a vector [TYPE START END] where TYPE is either char-ref
-or entity-ref and START and END are integers giving the start and end
-of the reference. Nested entity references are not included in the list."
+or entity-ref and START and END are integers giving the start and end of
+the reference.  Nested entity references are not included in the list."
   (aref att 6))
 
 (defun xmltok-attribute-prefix (att)
@@ -269,9 +237,10 @@ of the reference. Nested entity references are not included in the list."
                                 value-begin
                                 value-end
                                 raw-normalized-value)
-  "Make an attribute.  RAW-NORMALIZED-VALUE is nil if the value is
-not well-formed, t if the normalized value is the string between
-VALUE-BEGIN and VALUE-END, otherwise a STRING giving the value."
+  "Make an attribute.
+RAW-NORMALIZED-VALUE is nil if the value is not well-formed,
+t if the normalized value is the string between VALUE-BEGIN
+and VALUE-END, otherwise a STRING giving the value."
   (vector name-begin
          name-colon
          name-end
@@ -299,14 +268,6 @@ VALUE-BEGIN and VALUE-END, otherwise a STRING giving the value."
                                 (or end (point)))
              xmltok-errors)))
 
-(defun xmltok-add-dependent (fun &optional start end &rest args)
-  (setq xmltok-dependent-regions
-       (cons (cons fun
-                   (cons (or start xmltok-start)
-                         (cons (or end (point-max))
-                               args)))
-             xmltok-dependent-regions)))
-
 (defun xmltok-forward ()
   (setq xmltok-start (point))
   (let* ((case-fold-search nil)
@@ -316,16 +277,14 @@ VALUE-BEGIN and VALUE-END, otherwise a STRING giving the value."
           (cond ((> space-count 0)
                  (setq xmltok-type 'space))
                 (t
-                 (goto-char (1+ (point)))
+                 (forward-char 1)
                  (xmltok-scan-after-lt))))
          ((eq ch ?\&)
           (cond ((> space-count 0)
                  (setq xmltok-type 'space))
                 (t
-                 (goto-char (1+ (point)))
-                 (xmltok-scan-after-amp
-                  (lambda (start end)
-                    (xmltok-handle-entity start end))))))
+                 (forward-char 1)
+                 (xmltok-scan-after-amp 'xmltok-handle-entity))))
          ((re-search-forward "[<&]\\|\\(]]>\\)" nil t)
           (cond ((not (match-beginning 1))
                  (goto-char (match-beginning 0))
@@ -353,8 +312,8 @@ VALUE-BEGIN and VALUE-END, otherwise a STRING giving the value."
   "Scan forward past the first special token starting at or after point.
 Return nil if there is no special token that starts before BOUND.
 CDATA sections, processing instructions and comments (and indeed
-anything starting with < following by ? or !) count
-as special.  Return the type of the token."
+anything starting with < following by ? or !) count as special.
+Return the type of the token."
   (when (re-search-forward "<[?!]" (1+ bound) t)
     (setq xmltok-start (match-beginning 0))
     (goto-char (1+ xmltok-start))
@@ -394,7 +353,7 @@ as special.  Return the type of the token."
             (cons (concat "\\(" ,sym "\\)") (cons ',name nil))
           (cons (concat "\\(" (car ,sym) "\\)") (cons ',name (cdr ,sym)))))))
 
-  (defun xmltok-p (&rest r) (xmltok+ "\\(?:" 
+  (defun xmltok-p (&rest r) (xmltok+ "\\(?:"
                                     (apply 'xmltok+ r)
                                     "\\)"))
 
@@ -445,12 +404,11 @@ as special.  Return the type of the token."
                        (list 'match-string-no-properties
                              (xmltok-get-index group-name ',(cdr r))))
                       (t (error "Invalid action: %s" action))))))))
-  
+
 
 (eval-when-compile
   (let* ((or "\\|")
         (open "\\(?:")
-        (gopen "\\(")
         (close "\\)")
         (name-start-char "[_[:alpha:]]")
         (name-continue-not-start-char "[-.[:digit:]]")
@@ -687,14 +645,8 @@ as special.  Return the type of the token."
                (setq xmltok-type 'empty-element))
               ((xmltok-after-lt start cdata-section-open)
                (setq xmltok-type
-                     (if (search-forward "]]>" nil t)
-                         'cdata-section
-                       (xmltok-add-error "No closing ]]>")
-                       (xmltok-add-dependent 'xmltok-unclosed-reparse-p
-                                             nil
-                                             nil
-                                             "]]>")
-                       'not-well-formed)))
+                     (progn (search-forward "]]>" nil 'move)
+                             'cdata-section)))
               ((xmltok-after-lt start processing-instruction-question)
                (xmltok-scan-after-processing-instruction-open))
               ((xmltok-after-lt start comment-open)
@@ -761,68 +713,45 @@ as special.  Return the type of the token."
 ;; xmltok-scan-prolog-after-processing-instruction-open
 ;; XXX maybe should include rest of line (up to any <,>) in unclosed PI
 (defun xmltok-scan-after-processing-instruction-open ()
-  (cond ((not (search-forward "?>" nil t))
-        (xmltok-add-error "No closing ?>"
-                          xmltok-start
-                          (+ xmltok-start 2))
-        (xmltok-add-dependent 'xmltok-unclosed-reparse-p
-                              nil
-                              nil
-                              "?>")
-        (setq xmltok-type 'not-well-formed))
-       (t
-        (cond ((not (save-excursion
-                      (goto-char (+ 2 xmltok-start))
-                      (and (looking-at (xmltok-ncname regexp))
-                           (setq xmltok-name-end (match-end 0)))))
-               (setq xmltok-name-end (+ xmltok-start 2))
-               (xmltok-add-error "<? not followed by name"
-                                 (+ xmltok-start 2)
-                                 (+ xmltok-start 3)))
-              ((not (or (memq (char-after xmltok-name-end)
-                              '(?\n ?\t ?\r ? ))
-                        (= xmltok-name-end (- (point) 2))))
-               (xmltok-add-error "Target not followed by whitespace"
-                                 xmltok-name-end
-                                 (1+ xmltok-name-end)))
-              ((and (= xmltok-name-end (+ xmltok-start 5))
-                    (save-excursion
-                      (goto-char (+ xmltok-start 2))
-                      (let ((case-fold-search t))
-                        (looking-at "xml"))))
-               (xmltok-add-error "Processing instruction target is xml"
-                                 (+ xmltok-start 2)
-                                 (+ xmltok-start 5))))
-        (setq xmltok-type 'processing-instruction))))
-               
+  (search-forward "?>" nil 'move)
+  (cond ((not (save-excursion
+                (goto-char (+ 2 xmltok-start))
+                (and (looking-at (xmltok-ncname regexp))
+                     (setq xmltok-name-end (match-end 0)))))
+         (setq xmltok-name-end (+ xmltok-start 2))
+         (xmltok-add-error "<? not followed by name"
+                           (+ xmltok-start 2)
+                           (+ xmltok-start 3)))
+        ((not (or (memq (char-after xmltok-name-end)
+                        '(?\n ?\t ?\r ? ))
+                  (= xmltok-name-end (- (point) 2))))
+         (xmltok-add-error "Target not followed by whitespace"
+                           xmltok-name-end
+                           (1+ xmltok-name-end)))
+        ((and (= xmltok-name-end (+ xmltok-start 5))
+              (save-excursion
+                (goto-char (+ xmltok-start 2))
+                (let ((case-fold-search t))
+                  (looking-at "xml"))))
+         (xmltok-add-error "Processing instruction target is xml"
+                           (+ xmltok-start 2)
+                           (+ xmltok-start 5))))
+  (setq xmltok-type 'processing-instruction))
+
 (defun xmltok-scan-after-comment-open ()
-  (setq xmltok-type
-       (cond ((not (search-forward "--" nil t))
-              (xmltok-add-error "No closing -->")
-              (xmltok-add-dependent 'xmltok-unclosed-reparse-p
-                                    nil
-                                    nil
-                                    ;; not --> because
-                                    ;; -- is not allowed
-                                    ;; in comments in XML
-                                    "--")
-              'not-well-formed)
-             ((eq (char-after) ?>)
-              (goto-char (1+ (point)))
-              'comment)
-             (t
-              (xmltok-add-dependent
-               'xmltok-semi-closed-reparse-p
-               nil
-               (point)
-               "--"
-               2)
-              ;; just include the <!-- in the token
-              (goto-char (+ xmltok-start 4))
-              ;; Need do this after the goto-char because
-              ;; marked error should just apply to <!--
-              (xmltok-add-error "First following `--' not followed by `>'")
-              'not-well-formed))))
+  (let ((found-- (search-forward "--" nil 'move)))
+    (setq xmltok-type
+          (cond ((or (eq (char-after) ?>) (not found--))
+                 (goto-char (1+ (point)))
+                 'comment)
+                (t
+                 ;; just include the <!-- in the token
+                 (goto-char (+ xmltok-start 4))
+                 ;; Need do this after the goto-char because
+                 ;; marked error should just apply to <!--
+                 (xmltok-add-error "First following `--' not followed by `>'")
+                 (goto-char (point-max))
+                 'comment)))))
 
 (defun xmltok-scan-attributes ()
   (let ((recovering nil)
@@ -934,7 +863,7 @@ as special.  Return the type of the token."
            (cons att xmltok-attributes)))
     (and needs-normalizing
         att)))
-        
+
 (defun xmltok-normalize-attribute (att)
   (let ((end (xmltok-attribute-value-end att))
        (well-formed t)
@@ -1057,35 +986,8 @@ as special.  Return the type of the token."
         (xmltok-valid-char-p n)
         n)))
 
-(defun xmltok-unclosed-reparse-p (change-start
-                                 change-end
-                                 pre-change-length
-                                 start
-                                 end
-                                 delimiter)
-  (let ((len-1 (1- (length delimiter))))
-    (goto-char (max start (- change-start len-1)))
-    (search-forward delimiter (min end (+ change-end len-1)) t)))
-
-;; Handles a <!-- with the next -- not followed by >
-
-(defun xmltok-semi-closed-reparse-p (change-start
-                                    change-end
-                                    pre-change-length
-                                    start
-                                    end
-                                    delimiter
-                                    delimiter-length)
-  (or (<= (- end delimiter-length) change-end)
-      (xmltok-unclosed-reparse-p change-start
-                                change-end
-                                pre-change-length
-                                start
-                                end
-                                delimiter)))
-
 (defun xmltok-valid-char-p (n)
-  "Return non-nil if n is the Unicode code of a valid XML character."
+  "Return non-nil if N is the Unicode code of a valid XML character."
   (cond ((< n #x20) (memq n '(#xA #xD #x9)))
        ((< n #xD800) t)
        ((< n #xE000) nil)
@@ -1106,7 +1008,7 @@ Return nil if unsupported in Emacs."
 (defvar xmltok-had-param-entity-ref nil)
 (defvar xmltok-prolog-regions nil)
 (defvar xmltok-standalone nil
-  "Non-nil if there was an XML declaration specifying standalone=\"yes\",")
+  "Non-nil if there was an XML declaration specifying standalone=\"yes\".")
 (defvar xmltok-markup-declaration-doctype-flag nil)
 
 (defconst xmltok-predefined-entity-alist
@@ -1124,10 +1026,10 @@ START and END are integers giving the start and end of the region of
 that type.  TYPE can be one of xml-declaration,
 xml-declaration-attribute-name, xml-declaration-attribute-value,
 comment, processing-instruction-left, processing-instruction-right,
-markup-declaration-open markup-declaration-close,
+markup-declaration-open, markup-declaration-close,
 internal-subset-open, internal-subset-close, hash-name, keyword,
 literal, encoding-name.
-Adds to `xmltok-errors' and `xmltok-dependent-regions' as appropriate."
+Adds to `xmltok-errors' as appropriate."
   (let ((case-fold-search nil)
        xmltok-start
        xmltok-type
@@ -1141,7 +1043,7 @@ Adds to `xmltok-errors' and `xmltok-dependent-regions' as appropriate."
     (setq xmltok-dtd xmltok-predefined-entity-alist)
     (xmltok-scan-xml-declaration)
     (xmltok-next-prolog-token)
-    (while (condition-case err
+    (while (condition-case nil
               (when (xmltok-parse-prolog-item)
                 (xmltok-next-prolog-token))
             (xmltok-markup-declaration-parse-error
@@ -1151,7 +1053,6 @@ Adds to `xmltok-errors' and `xmltok-dependent-regions' as appropriate."
                        (1- xmltok-internal-subset-start)
                        xmltok-internal-subset-start))
     (xmltok-parse-entities)
-    ;; XXX prune dependent-regions for those entirely in prolog
     (nreverse xmltok-prolog-regions)))
 
 (defconst xmltok-bad-xml-decl-regexp
@@ -1165,8 +1066,8 @@ contains an encoding declaration, then return (START . END)
 where START and END are the positions of the start and the end
 of the encoding name; if there is no encoding declaration return
 the position where and encoding declaration could be inserted.
-If there is XML that is not well-formed that looks like an XML declaration,
-return nil.  Otherwise, return t.
+If there is XML that is not well-formed that looks like an XML
+declaration, return nil.  Otherwise, return t.
 If LIMIT is non-nil, then do not consider characters beyond LIMIT."
   (cond ((let ((case-fold-search nil))
           (and (looking-at (xmltok-xml-declaration regexp))
@@ -1179,7 +1080,7 @@ If LIMIT is non-nil, then do not consider characters beyond LIMIT."
                 (+ (point) 5)))))
        ((not (let ((case-fold-search t))
                (looking-at xmltok-bad-xml-decl-regexp))))))
-               
+
 (defun xmltok-scan-xml-declaration ()
   (when (looking-at (xmltok-xml-declaration regexp))
     (xmltok-add-prolog-region 'xml-declaration (point) (match-end 0))
@@ -1339,7 +1240,7 @@ If LIMIT is non-nil, then do not consider characters beyond LIMIT."
             (when (string= (xmltok-current-token-string) "#FIXED")
               (xmltok-require-next-token 'literal))
             t))))
-                  
+
 (defun xmltok-parse-nmtoken-group ()
   (while (progn
           (xmltok-require-next-token 'nmtoken 'prefixed-name 'name)
@@ -1380,7 +1281,7 @@ If LIMIT is non-nil, then do not consider characters beyond LIMIT."
                                          'close-paren-star
                                          'close-paren-occur)
               (eq xmltok-type connector))))))
-                                         
+
 (defun xmltok-parse-model-group-member ()
   (xmltok-require-token 'name
                        'prefixed-name
@@ -1389,7 +1290,7 @@ If LIMIT is non-nil, then do not consider characters beyond LIMIT."
   (when (eq xmltok-type ?\()
     (xmltok-next-prolog-token)
     (xmltok-parse-model-group)))
-    
+
 (defun xmltok-parse-entity-declaration ()
   (let (paramp name)
     (xmltok-require-next-token 'name ?%)
@@ -1420,7 +1321,7 @@ If LIMIT is non-nil, then do not consider characters beyond LIMIT."
             (not (assoc name xmltok-dtd)))
     (setq xmltok-dtd
          (cons (cons name value) xmltok-dtd))))
-  
+
 (defun xmltok-parse-entity-value ()
   (let ((lim (1- (point)))
        (well-formed t)
@@ -1441,7 +1342,7 @@ If LIMIT is non-nil, then do not consider characters beyond LIMIT."
                       (t
                        (let ((xmltok-start (1- (point)))
                               xmltok-type xmltok-replacement)
-                         (xmltok-scan-after-amp (lambda (start end)))
+                         (xmltok-scan-after-amp (lambda (_start _end)))
                          (cond ((eq xmltok-type 'char-ref)
                                 (setq value-parts
                                       (cons (buffer-substring-no-properties
@@ -1460,7 +1361,7 @@ If LIMIT is non-nil, then do not consider characters beyond LIMIT."
       (apply 'concat
             (nreverse (cons (buffer-substring-no-properties start lim)
                             value-parts))))))
-                    
+
 (defun xmltok-parse-notation-declaration ()
   (xmltok-require-next-token 'name)
   (xmltok-require-next-token "SYSTEM" "PUBLIC")
@@ -1505,13 +1406,8 @@ If LIMIT is non-nil, then do not consider characters beyond LIMIT."
 (defun xmltok-current-token-string ()
   (buffer-substring-no-properties xmltok-start (point)))
 
-(put 'xmltok-markup-declaration-parse-error
-     'error-conditions
-     '(error xmltok-markup-declaration-parse-error))
-
-(put 'xmltok-markup-declaration-parse-error
-     'error-message
-     "Syntax error in markup declaration")
+(define-error 'xmltok-markup-declaration-parse-error
+  "Syntax error in markup declaration")
 
 (defun xmltok-markup-declaration-parse-error ()
   (signal 'xmltok-markup-declaration-parse-error nil))
@@ -1545,9 +1441,9 @@ If LIMIT is non-nil, then do not consider characters beyond LIMIT."
                      (hash-name . hash-name)))))
        ((and (stringp required) (eq xmltok-type 'name))
         'keyword)))
-        
+
 ;; Return new token type.
-                                   
+
 (defun xmltok-next-prolog-token ()
   (skip-chars-forward " \t\r\n")
   (setq xmltok-start (point))
@@ -1575,13 +1471,13 @@ If LIMIT is non-nil, then do not consider characters beyond LIMIT."
         (unless (looking-at "[ \t\r\n>),|[%]")
           (xmltok-add-error "Missing space after name token"))
         (setq xmltok-type 'nmtoken))
-       ((xmltok-prolog start name)     
+       ((xmltok-prolog start name)
         (setq xmltok-name-end (point))
         (setq xmltok-name-colon nil)
         (unless (looking-at "[ \t\r\n>),|[%]")
           (xmltok-add-error "Missing space after name"))
         (setq xmltok-type 'name))
-       ((xmltok-prolog start hash-name)        
+       ((xmltok-prolog start hash-name)
         (setq xmltok-name-end (point))
         (unless (looking-at "[ \t\r\n>)|%]")
           (xmltok-add-error "Missing space after name"))
@@ -1651,95 +1547,68 @@ If LIMIT is non-nil, then do not consider characters beyond LIMIT."
         (end (save-excursion
                (goto-char safe-end)
                (search-forward delim nil t))))
-    (or (cond ((not end)
-              (xmltok-add-dependent 'xmltok-unclosed-reparse-p
-                                    nil
-                                    nil
-                                    delim)
-              nil)
-             ((save-excursion
-                (goto-char end)
-                (looking-at "[ \t\r\n>%[]"))
-              (goto-char end)
-              (setq xmltok-type 'literal))
-             ((eq (1+ safe-end) end)
-              (goto-char end)
-              (xmltok-add-error (format "Missing space after %s" delim)
-                                safe-end)
-              (setq xmltok-type 'literal))
-             (t
-              (xmltok-add-dependent 'xmltok-semi-closed-reparse-p
-                                    xmltok-start
-                                    (1+ end)
-                                    delim
-                                    1)
-              nil))
-       (progn
-         (xmltok-add-error (format "Missing closing %s" delim))
-         (goto-char safe-end)
-         (skip-chars-backward " \t\r\n")
-         (setq xmltok-type 'not-well-formed)))))
+    (cond ((or (not end)
+               (save-excursion
+                 (goto-char end)
+                 (looking-at "[ \t\r\n>%[]")))
+           (goto-char end))
+          ((eq (1+ safe-end) end)
+           (goto-char end)
+           (xmltok-add-error (format "Missing space after %s" delim)
+                             safe-end)))
+    (setq xmltok-type 'literal)))
 
 (defun xmltok-scan-prolog-after-processing-instruction-open ()
-  (cond ((not (search-forward "?>" nil t))
-        (xmltok-add-error "No closing ?>"
-                          xmltok-start
-                          (+ xmltok-start 2))
-        (xmltok-add-dependent 'xmltok-unclosed-reparse-p
-                              nil
-                              nil
-                              "?>")
-        (setq xmltok-type 'not-well-formed))
-       (t
-        (let* ((end (point))
-               (target
-                (save-excursion
-                  (goto-char (+ xmltok-start 2))
-                  (and (looking-at (xmltok-ncname regexp))
-                       (or (memq (char-after (match-end 0))
-                                 '(?\n ?\t ?\r ? ))
-                           (= (match-end 0) (- end 2)))
-                       (match-string-no-properties 0)))))
-          (cond ((not target)
-                 (xmltok-add-error "\
+  (search-forward "?>" nil 'move)
+  (let* ((end (point))
+         (target
+          (save-excursion
+            (goto-char (+ xmltok-start 2))
+            (and (looking-at (xmltok-ncname regexp))
+                 (or (memq (char-after (match-end 0))
+                           '(?\n ?\t ?\r ? ))
+                     (= (match-end 0) (- end 2)))
+                 (match-string-no-properties 0)))))
+    (cond ((not target)
+           (xmltok-add-error "\
 Processing instruction does not start with a name"
-                                   (+ xmltok-start 2)
-                                   (+ xmltok-start 3)))
-                ((not (and (= (length target) 3)
-                           (let ((case-fold-search t))
-                             (string-match "xml" target)))))
-                ((= xmltok-start 1)
-                 (xmltok-add-error "Invalid XML declaration"
-                                   xmltok-start
-                                   (point)))
-                ((save-excursion
-                   (goto-char xmltok-start)
-                   (looking-at (xmltok-xml-declaration regexp)))
-                 (xmltok-add-error "XML declaration not at beginning of file"
-                                   xmltok-start
-                                   (point)))
-                (t
-                 (xmltok-add-error "Processing instruction has target of xml"
-                                   (+ xmltok-start 2)
-                                   (+ xmltok-start 5))))
-          (xmltok-add-prolog-region 'processing-instruction-left
-                                    xmltok-start
-                                    (+ xmltok-start
-                                       2
-                                       (if target
-                                           (length target)
-                                         0)))
-          (xmltok-add-prolog-region 'processing-instruction-right
-                                    (if target
-                                        (save-excursion
-                                          (goto-char (+ xmltok-start
-                                                        (length target)
-                                                        2))
-                                          (skip-chars-forward " \t\r\n")
-                                          (point))
-                                      (+ xmltok-start 2))
-                                    (point)))
-        (setq xmltok-type 'processing-instruction))))
+                             (+ xmltok-start 2)
+                             (+ xmltok-start 3)))
+          ((not (and (= (length target) 3)
+                     (let ((case-fold-search t))
+                       (string-match "xml" target)))))
+          ((= xmltok-start 1)
+           (xmltok-add-error "Invalid XML declaration"
+                             xmltok-start
+                             (point)))
+          ((save-excursion
+             (goto-char xmltok-start)
+             (looking-at (xmltok-xml-declaration regexp)))
+           (xmltok-add-error "XML declaration not at beginning of file"
+                             xmltok-start
+                             (point)))
+          (t
+           (xmltok-add-error "Processing instruction has target of xml"
+                             (+ xmltok-start 2)
+                             (+ xmltok-start 5))))
+    (xmltok-add-prolog-region 'processing-instruction-left
+                              xmltok-start
+                              (+ xmltok-start
+                                 2
+                                 (if target
+                                     (length target)
+                                   0)))
+    (xmltok-add-prolog-region 'processing-instruction-right
+                              (if target
+                                  (save-excursion
+                                    (goto-char (+ xmltok-start
+                                                  (length target)
+                                                  2))
+                                    (skip-chars-forward " \t\r\n")
+                                    (point))
+                                (+ xmltok-start 2))
+                              (point)))
+  (setq xmltok-type 'processing-instruction))
 
 (defun xmltok-parse-entities ()
   (let ((todo xmltok-dtd))
@@ -1750,10 +1619,10 @@ Processing instruction does not start with a name"
     (while todo
       (xmltok-parse-entity (car todo))
       (setq todo (cdr todo)))))
-  
+
 (defun xmltok-parse-entity (name-def)
   (let ((def (cdr name-def))
-       ;; in case its value is buffer local 
+       ;; in case its value is buffer local
        (xmltok-dtd xmltok-dtd)
        buf)
     (when (stringp def)
@@ -1762,8 +1631,7 @@ Processing instruction does not start with a name"
        (setcdr name-def 'not-well-formed) ; avoid infinite expansion loops
        (setq buf (get-buffer-create
                   (format " *Entity %s*" (car name-def))))
-       (save-excursion
-         (set-buffer buf)
+       (with-current-buffer buf
          (erase-buffer)
          (insert def)
          (goto-char (point-min))
@@ -1857,7 +1725,7 @@ Processing instruction does not start with a name"
                   'not-well-formed))
                ((eq def 'unparsed) 'not-well-formed)
                (t def)))))
-    
+
 (defun xmltok-append-entity-def (d1 d2)
   (cond ((consp d1)
         (if (consp d2)
@@ -1880,7 +1748,7 @@ Processing instruction does not start with a name"
              xmltok-prolog-regions)))
 
 (defun xmltok-merge-attributes ()
-  "Return a list merging `xmltok-attributes' and 'xmltok-namespace-attributes'.
+  "Return a list merging `xmltok-attributes' and `xmltok-namespace-attributes'.
 The members of the merged list are in order of occurrence in the
 document.  The list may share list structure with `xmltok-attributes'
 and `xmltok-namespace-attributes'."
@@ -1924,5 +1792,4 @@ and `xmltok-namespace-attributes'."
 
 (provide 'xmltok)
 
-;; arch-tag: 747e5f3a-6fc3-4f8d-bd96-89f05aa99f5e
 ;;; xmltok.el ends here