Filewatcher File Search
FTP Search
  
Directory (beta)
  
Content Search (beta)
   
pkg://emacs-tdtd-0.7.1-4mdk.src.rpm:37231/emacs-tdtd-0.7.1.tar.bz2  info  downloads

tdtd/0040775000076500007650000000000007405417542011643 5ustar  camillecamilletdtd/TODO0100444000076500007650000000052206676775260012340 0ustar  camillecamille# $Id: TODO,v 1.1 1999/03/26 22:12:57 tkg Exp $
# $Name: tdtd071 $
font lock for FPI types
option to not prompt for comments
menus
no spaces when entering element, etc., names
form buffer for declarations
read catalog and find referenced modules
Lee Quin-style declarations
ESC TAB bound to info-complete-tag in some Emacs/XEmacstdtd/changelog.txt0100444000076500007650000001342006676775260014341 0ustar  camillecamilletdtd Change Log
===============
$Id: changelog.txt,v 1.11 1999/03/23 13:31:42 tkg Exp $
$Name: tdtd071 $

Revision 0.7.1, March 24, 1999
==============================

tdtd.el
-------

Added test for beginning of line before removing line end after
`fill-region' since Emacs 19.34 different from Emacs 20.3.

Corrected two spelling errors.

tdtd-font-maker.el
------------------

Added more initial comment in tdtd-font.el output.

added `dtd-make-safe-var-def' to fix problems with generated
tdtd-font.el.

tutorial.txt
------------

Added more variations on M-TAB in step 7.4 since `complete-symbol' in
Emacs 20.3 is backwards w.r.t. both its documentation and Emacs 19.34
behaviour.


Revision 0.7, February 22, 1999
===============================

tdtd.el
-------

Stopped being a derived mode.

Moved `require' forms to top of file where they'll be more visible.

Added support for detecting System Declaration and specific font-lock
keywords for XML DTDs, SGML DTDs, SGML Declarations, and System
Declarations.

Added `dtd-font-lock-region-point-min' and
`dtd-font-lock-region-point-max' in support of change to font locking
because of XEmacs.

Added dtd-grep-command-format for customising dtd-grep command.

Added imenu stuff.

Added `dtd-electric-mdc' so refontification happens even if you don't
use `dtd-insert-mdc'.

Added variables controlling prompting for descriptive names and
comments in element, etc. declarations.

Added `read-from-minibuffer' stuff for `declare-external-entity'.

Renamed dtd-autodetect-xml to dtd-autodetect-type since now also
detects SGML Declaration, now uses different font-lock keywords if
XML.

Changed all dtd-mode-map definitions to use XEmacs-compatible syntax.

Changed all `font-lock-fontify-block' to something that works with
XEmacs and that respects the current font-lock-mode value.

Added test to not print name comments if no content.

Added 1999 to copyright years.

tdtd-font.el
------------

Renamed to `tdtd-font-maker.el'.  `tdtd-font.el' now created by
`dtd-make-tdtd-font' function in `tdtd-font-maker.el'.

tdtd-font-maker.el
------------------

Renamed from `tdtd-font.el'.

Added `dtd-make-tdtd-font'.

Major rework to support different sets of font-lock keywords for XML
DTDs, SGML DTDs, SGML Declarations, and System Declarations.

Added 1999 to copyright years

tutorial.txt
------------

Fixed a typo, added example of using "Goto" menu.

dot_emacs
---------

Added autoloads for `dtd-etags' and `dtd-grep', added .ele to
auto-mode-alist


Revision 0.6, August 1, 1998
==========================

tdtd.el
-------

Added dtd-grep.

Added dtd-submit-bug-report.

Added functions for attribute lists, parameter entities, external
entities, and notations.

Added lots of minibuffer histories, added many prompted defaults, and
added `dtd-read-from-minibuffer'.

Folded `dtd-big-comment' processing into `dtd-comment'.

Changed some keymaps.

Added more to `dtd-find-tag-hook'.

Added dtd-outdent-attribute-pe variable and added variables and
support for different indents for content models in XML element
declarations.

Changed ">=" to ">" in `dtd-indent-or-newline-to'.

Added recreating dtd-declared-element-type-names as part of dtd-etags.

Added "<" and ">" to syntax table as punctuation characters.

Added dtd-design-comment-start.

Removed useless `dtd-startup'.

Changed parameter entity value indent column.

Made all `re-search-forward' and `re-search-backward' not throw error
on no match.

Added dtd-upcase-name-comment-flag.

tdtd-font.el
------------

Removed brain-dead #EMPTY keyword and reinserted EMPTY, added DTD
keyword.


Revision 0.5.1, May 25, 1998
============================

tdtd-font.el
------------

Minor change to implicit and explicit link regular expressions that
were causing problems with XEmacs 20.4.


Revision 0.5, May 25, 1998
============================

tdtd.el
-------

Added dtd-etags stuff and syntax table stuff.

Moved dtd-mode definition here since finally got autoload to work.

Added more variable and function comments, changed many hard-coded
strings to values computed from variables, and changed many of the
variables for indent columns to be column at which to leave point and
used (1- value) when computing prefix strings, etc.

Changed all tdtd- to dtd- in variable and function names since using
the mode name, not the package name, as the prefix is the preferred
elisp style.

Moved turning font lock on out of dtd-mode definition so user has a
choice.

Changed most setq to defvar so user can override in their .emacs file.

Added some XML smarts, including autodetection of XML Declaration.

Added dtd-indent-tabs-mode to control setting indent-tabs-mode on
entering dtd-mode.

tdtd-font.el
------------

Changed all tdtd- to dtd- to match mode name.

Added more regular expressions for font lock of processing
instructions.

Changed order of parameter entity font lock regular expression so
"<!ELEMENT %pe;" works properly.


Revision 0.4, April 21, 1998
============================

tdtd-font.el
------------

Added \\b...\\b around reserved word regular expression so only
matches on whole words, not on reserved words appearing within words.
Required rearranging regular expression for reserved words starting
with '#' plus '(ENR)', '(WWW)', '+//', '-//', and '//'.

Added '(WWW)' and 'xml' as reserved words


Revision 0.3, December 14, 1997
===============================

tdtd.el
-------

Fixed bug with lines with just "-->" in tdtd-insert-mdc.  Started
playing with tdtd-fill-paragraph.

tdtd-font.el
------------

Added XML as keyword, added XML PI, XML-style element declaration,
SHORTREF declaration, and USEMAP declaration.

tdtd/dot_emacs0100444000076500007650000000137506676775260013540 0ustar  camillecamille;; $Id: dot_emacs,v 1.5 1999/02/15 17:43:33 tkg Exp $

;; DTD mode
(autoload 'dtd-mode "tdtd" "Major mode for SGML and XML DTDs." t)
(autoload 'dtd-etags "tdtd"
  "Execute etags on FILESPEC and match on DTD-specific regular expressions."
  t)
(autoload 'dtd-grep "tdtd" "Grep for PATTERN in files matching FILESPEC." t)

;; Turn on font lock when in DTD mode
(add-hook 'dtd-mode-hooks
	  'turn-on-font-lock)

(setq auto-mode-alist
      (append
       (list
	'("\\.dcl$" . dtd-mode)
	'("\\.dec$" . dtd-mode)
	'("\\.dtd$" . dtd-mode)
	'("\\.ele$" . dtd-mode)
	'("\\.ent$" . dtd-mode)
	'("\\.mod$" . dtd-mode))
       auto-mode-alist))

;; To use resize-minibuffer-mode, uncomment this and include in your .emacs:
;;(resize-minibuffer-mode)
tdtd/readme.txt0100444000076500007650000001172606676775260013656 0ustar  camillecamilleThis package contains an emacs major mode for editing SGML and XML
DTDs.  The current revision is 0.7.1, dated March 24, 1999.

The tdtd home page is http://www.mulberrytech.com/tdtd/


* MANIFEST

File                            Contents

readme.txt                      The file you are reading
dot_emacs                       Some things for your .emacs file
tdtd.el                         A collection of DTD-related procedures
tdtd-font.el                    Font lock keywords for DTDs
tdtd-font-maker.el              Data and procedure to create tdtd-font.el
make-regexp.el                  Used by tdtd-font-maker.el
changelog.txt                   List of changes
tutorial.txt                    A tutorial on using dtd-mode


* FEATURES

 - Standalone mode for editing DTDs;

 - "Goto" menu for locating declarations within the current buffer;

 - `dtd-etags' function for creating Emacs TAGS files for easy lookup
   across multiple files of any element, parameter entity, or
   notation's definition using Emacs's built-in tag-lookup functions;

 - `dtd-grep' function for searching files that shares a file history
   with `dtd-etags' for easy searching of the same files with both
   functions;

 - Specific font lock highlighting of declarations in XML DTDs, SGML
   DTDs, SGML Declarations, and System Declarations so that the
   important information stands out;

 - XML-specific behaviour that, at user option, is triggered by
   automatic detection of the XML Declaration; 

 - Functions for writing and editing element, attribute, internal
   parameter entity and external parameter entity declarations and
   comments to ease creating and keeping a consistent style; and

 - Elements and parameter entity names referenced in declarations are
   stored in minibuffer history to minimise retyping in new
   declarations.

dtd-mode references `sgml-validate' for its validation function.  Use
with Lennart Staflin's psgml package is recommended.

Use with resize-minibuffer-mode is also recommended.

The "Goto" menu is only available if you have imenu.el.

dtd-mode was tested using NTEmacs 20.3.1.

* FORMATTING VARIABLES

dtd-mode uses many user-definable variables to control the formatting
of declarations, some of which are shown in the following examples:

                        dtd-comment-start-column    dtd-dtd-max-column
                        |                    dtd-comment-max-column  |
                        |                                         |  |
<!--                    This is a comment                          -->

           dtd-element-name-column
           |            dtd-element-tag-ommission-column
           |            |   dtd-element-content-spec-start-column
           |            |   |dtd-element-content-spec-continuation-column
           |            |   ||                      dtd-dtd-max-column
           |            |   ||                                       |
<!ELEMENT  element-tag  - - (insert, your, content, specification,
                             here)                                   >

* BUG REPORTS/ENCHANCEMENTS

I would be glad to accept bug reports and/or enhancements.

* INSTALLATION

1. Unzip the distribution.

   This should extract the files listed in the manifest above.

   tdtd is authored on a PC.  Make sure that the files are unzipped
   with the correct line endings for your platform.

2. Copy the tdtd.el and tdtd-font.el files to your emacs site-lisp
   directory (e.g., /usr/local/lib/emacs/site-lisp).

   XEmacs users also need to make sure that they have imenu.el
   installed before they can use the "Goto" menu.

3. Byte compile tdtd.el and tdtd-font.el using M-x byte-compile-file
   and supplying the path name of each file.

   If you byte-compiled a previous version of tdtd.el and
   tdtd-font.el, then you must byte-compile the new files (or remove
   the old .elc files) so that autoload loads the correct versions.

   If you do not have imenu.el, you may receive a "assignment to free
   variable imenu-create-index-function" warning when you byte compile
   tdtd.el.  You will, however, be able to use the compiled tdtd.elc
   without error (and without the "Goto" menu).

   You do not need tdtd-font-maker.el or make-regexp.el in order to
   use tdtd.  They are provided in case you want to modify the
   font-lock regular expressions and remake tdtd-font.el.

4. Add the elisp code in dot_emacs to your .emacs file.

5. When you visit a file with an extension of .dtd, etc., dtd-mode
   will automatically be loaded.


* MAKING tdtd-font.el

tdtd-font.el is created by tdtd-font-maker.el.  You should not need to
remake tdtd-font.el unless you have tinkered with the regular
expressions in tdtd-font-maker.el.

1. Load file `tdtd-font-maker.el'.

2. Execute `dtd-make-tdtd-font'.

   tdtd-font.el is created in the current directory.

-----
$Id: readme.txt,v 1.17 1999/03/23 13:19:55 tkg Exp $
$Name: tdtd071 $
tdtd/make-regexp.el0100444000076500007650000003153606604145320014363 0ustar  camillecamille;;; make-regexp.el --- generate efficient regexps to match strings.

;; Copyright (C) 1994, 1995 Simon Marshall.

;; Author: Simon Marshall <simon@gnu.ai.mit.edu>
;; Keywords: strings, regexps
;; Version: 1.02

;; LCD Archive Entry:
;; make-regexp|Simon Marshall|simon@gnu.ai.mit.edu|
;; Generate efficient regexps to match strings.|
;; 11-Jul-1995|1.02|~/functions/make-regexp.el.gz|

;; The archive is archive.cis.ohio-state.edu in /pub/gnu/emacs/elisp-archive.

;;; This file is not part of GNU Emacs.

;;; 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, 675 Mass Ave, Cambridge, MA 02139, USA.

;;; Commentary:

;; Purpose:
;;
;; To make efficient regexps from lists of strings.

;; For example:
;;
;; (let ((strings '("cond" "if" "while" "let\\*?" "prog1" "prog2" "progn"
;;                  "catch" "throw" "save-restriction" "save-excursion"
;;                  "save-window-excursion" "save-match-data"
;;                  "unwind-protect" "condition-case" "track-mouse")))
;;   (concat "(" (make-regexp strings t)))
;;
;;      => "(\\(c\\(atch\\|ond\\(\\|ition-case\\)\\)\\|if\\|let\\*?\\|prog[12n]\\|save-\\(excursion\\|match-data\\|restriction\\|window-excursion\\)\\|t\\(hrow\\|rack-mouse\\)\\|unwind-protect\\|while\\)"
;;
;; To search for the above regexp takes about 70% of the time as for the simple
;; (concat "(\\(" (mapconcat 'identity strings "\\|") "\\)") regexp.
;;
;; Obviously, the more the similarity between strings, the faster the regexp:
;;
;; (make-regexp '("abort" "abs" "accept" "access" "array" "begin" "body" "case"
;;                "constant" "declare" "delay" "delta" "digits" "else" "elsif"
;;                "entry" "exception" "exit" "function"  "generic" "goto" "if"
;;                "others" "limited" "loop" "mod" "new" "null" "out" "subtype"
;;                "package" "pragma" "private" "procedure" "raise" "range"
;;                "record" "rem" "renames" "return" "reverse" "select"
;;                "separate" "task" "terminate" "then" "type" "when" "while"
;;                "with" "xor"))
;;
;;     => "a\\(b\\(ort\\|s\\)\\|cce\\(pt\\|ss\\)\\|rray\\)\\|b\\(egin\\|ody\\)\\|c\\(ase\\|onstant\\)\\|d\\(e\\(clare\\|l\\(ay\\|ta\\)\\)\\|igits\\)\\|e\\(ls\\(e\\|if\\)\\|ntry\\|x\\(ception\\|it\\)\\)\\|function\\|g\\(eneric\\|oto\\)\\|if\\|l\\(imited\\|oop\\)\\|mod\\|n\\(ew\\|ull\\)\\|o\\(thers\\|ut\\)\\|p\\(ackage\\|r\\(agma\\|ivate\\|ocedure\\)\\)\\|r\\(a\\(ise\\|nge\\)\\|e\\(cord\\|m\\|names\\|turn\\|verse\\)\\)\\|s\\(e\\(lect\\|parate\\)\\|ubtype\\)\\|t\\(ask\\|erminate\\|hen\\|ype\\)\\|w\\(h\\(en\\|ile\\)\\|ith\\)\\|xor"
;;
;; To search for the above regexp takes less than 60% of the time of the simple
;; mapconcat equivalent.
;;
;; But even small regexps may be worth it:
;;
;; (make-regexp '("and" "at" "do" "end" "for" "in" "is" "not" "of" "or" "use"))
;;     => "a\\(nd\\|t\\)\\|do\\|end\\|for\\|i[ns]\\|not\\|o[fr]\\|use"
;;
;; as this is 10% faster than the mapconcat equivalent.

;; Installation:
;; 
;; (autoload 'make-regexp "make-regexp"
;;   "Return a regexp to match a string item in STRINGS.")
;;
;; (autoload 'make-regexps "make-regexp"
;;   "Return a regexp to REGEXPS.")
;;
;; Since these functions were written to produce efficient regexps, not regexps
;; efficiently, it is probably not a good idea to in-line too many calls in
;; your code, unless you use the following neat trick with `eval-when-compile':
;;
;; (defvar definition-regexp
;;   (let ((regexp (eval-when-compile
;;                   (make-regexp '("defun" "defsubst" "defmacro" "defalias"
;;                                  "defvar" "defconst" "defadvice") t))))
;;     (concat "^(" regexp)))
;;
;; The `byte-compile' code will be as if you had defined the variable thus:
;;
;; (defvar definition-regexp
;;   "^(\\(def\\(a\\(dvice\\|lias\\)\\|const\\|macro\\|subst\\|un\\|var\\)\\)")

;; Feedback:
;;
;; Originally written for font-lock, from an idea from Stig's hl319.
;; Please don't tell me that it doesn't produce optimal regexps; I know that
;; already.  But (ideas or) code to improve things (are) is welcome.  Please
;; test your code and tell me the speed up in searching an appropriate buffer.
;;
;; Please send me bug reports, bug fixes, and extensions, etc.
;; Simon Marshall <simon@gnu.ai.mit.edu>

;; History:
;;
;; 1.00--1.01:
;; - Made `make-regexp' take `lax' to force top-level parentheses.
;; - Fixed `make-regexps' for MATCH bug and new `font-lock-keywords'.
;; - Added `unfontify' to user timing functions.
;; 1.01--1.02:
;; - Made `make-regexp' `let' a big `max-lisp-eval-depth'.

;; The basic idea is to find the shortest common non-"" prefix each time, and
;; squirrel it out.  If there is no such prefix, we divide the list into two so
;; that (at least) one half will have at least a one-character common prefix.

;; In addition, we (a) delay the addition of () parenthesis as long as possible
;; (until we're sure we need them), and (b) try to squirrel out one-character
;; sequences (so we can use [] rather than ()).

(defun make-regexp (strings &optional paren lax)
  "Return a regexp to match a string item in STRINGS.
If optional PAREN non-nil, output regexp parentheses around returned regexp.
If optional LAX non-nil, don't output parentheses if it doesn't require them.
Merges keywords to avoid backtracking in Emacs' regexp matcher."
  (let* ((max-lisp-eval-depth (* 1024 1024))
	 (strings (let ((l strings))	; Paranoia---make strings unique!
		    (while l (setq l (setcdr l (delete (car l) (cdr l)))))
		    (sort strings 'string-lessp)))
	 (open-paren (if paren "\\(" "")) (close-paren (if paren "\\)" ""))
	 (open-lax (if lax "" open-paren)) (close-lax (if lax "" close-paren))
	 (completion-ignore-case nil))
    (cond
     ;; If there's only one string, just return it.
     ((= (length strings) 1)
      (concat open-lax (car strings) close-lax))
     ;; If there's an empty string, pull it out.
     ((string= (car strings) "")
      (if (and (= (length strings) 2) (= (length (nth 1 strings)) 1))
	  (concat open-lax (nth 1 strings) "?" close-lax)
	(concat open-paren "\\|" (make-regexp (cdr strings)) close-paren)))
     ;; If there are only one-character strings, make a [] list instead.
     ((= (length strings) (apply '+ (mapcar 'length strings)))
      (concat open-lax "[" (mapconcat 'identity strings "") "]" close-lax))
     (t
      ;; We have a list of strings.  Is there a common prefix?
      (let ((prefix (try-completion "" (mapcar 'list strings))))
	(if (> (length prefix) 0)
	    ;; Common prefix!  Squirrel it out and recurse with the suffixes.
	    (let* ((len (length prefix))
		   (sufs (mapcar '(lambda (str) (substring str len)) strings)))
	      (concat open-paren prefix (make-regexp sufs t t) close-paren))
	  ;; No common prefix.  Is there a one-character sequence?
	  (let ((letters (let ((completion-regexp-list '("^.$")))
			   (all-completions "" (mapcar 'list strings)))))
	    (if (> (length letters) 1)
		;; Do the one-character sequences, then recurse on the rest.
		(let ((rest (let ((completion-regexp-list '("^..+$")))
			      (all-completions "" (mapcar 'list strings)))))
		  (concat open-paren
			  (make-regexp letters) "\\|" (make-regexp rest)
			  close-paren))
	      ;; No one-character sequence, so divide the list into two by
	      ;; dividing into those that start with a particular letter, and
	      ;; those that do not.
	      (let* ((char (substring (car strings) 0 1))
		     (half1 (all-completions char (mapcar 'list strings)))
		     (half2 (nthcdr (length half1) strings)))
		(concat open-paren
			(make-regexp half1) "\\|" (make-regexp half2)
			close-paren))))))))))

;; This stuff is realy for font-lock...

;; Ahhh, the wonders of lisp...
(defun regexp-span (regexp &optional start)
  "Return the span or depth of REGEXP.
This means the number of \"\\\\(...\\\\)\" pairs in REGEXP, optionally from START."
  (let ((match (string-match (regexp-quote "\\(") regexp (or start 0))))
    (if (not match) 0 (1+ (regexp-span regexp (match-end 0))))))

;; The basic idea is to concat the regexps together, keeping count of the span
;; of the regexps so that we can get the correct match for hilighting.
(defun make-regexps (&rest regexps)
  "Return a regexp to match REGEXPS
Each item of REGEXPS should be of the form:

 STRING                                 ; A STRING to be used literally.
 (STRING MATCH FACE DATA)               ; Match STRING at depth MATCH with FACE
                                        ; and highlight according to DATA.
 (STRINGS FACE DATA)                    ; STRINGS is a list of strings FACE is
                                        ; to highlight according to DATA.

Returns a list of the form:

 (REGEXP (MATCH FACE DATA) ...)

For example:

 (make-regexps \"^(\"
               '((\"defun\" \"defalias\" \"defsubst\" \"defadvice\") keyword)
               \"[ \t]*\"
               '(\"\\\\([a-zA-Z-]+\\\\)?\" 1 function-name nil t))

     =>

 (\"^(\\\\(def\\\\(a\\\\(dvice\\\\|lias\\\\)\\\\|subst\\\\|un\\\\)\\\\)[ 	]*\\\\([a-zA-Z-]+\\\\)?\"
  (1 keyword) (4 function-name nil t))

Uses `make-regexp' to make efficient regexps."
  (let ((regexp "") (data ()))
    (while regexps
      (cond ((stringp (car regexps))
	     (setq regexp (concat regexp (car regexps))))
	    ((stringp (nth 0 (car regexps)))
	     (setq data (cons (cons (+ (regexp-span regexp)
				       (nth 1 (car regexps)))
				    (nthcdr 2 (car regexps)))
			      data)
		   regexp (concat regexp (nth 0 (car regexps)))))
	    (t
	     (setq data (cons (cons (1+ (regexp-span regexp))
				    (cdr (car regexps)))
			      data)
		   regexp (concat regexp (make-regexp (nth 0 (car regexps))
						      t)))))
      (setq regexps (cdr regexps)))
    (cons regexp (nreverse data))))

;; Crude-rude timing...

(defsubst time-seconds (&optional time)
  "Return the TIME in seconds, or the current time if not given.
TIME should be the same format as produced by `current-time'."
  (let ((time (or time (current-time))))
    (+ (* (nth 0 time) 65536.0) (nth 1 time) (/ (nth 2 time) 1000000.0))))

(defsubst time-since (time)
  "Return the time in seconds since TIME.
TIME should be the value of `current-time' or `time-seconds'."
  (- (time-seconds) (if (floatp time) time (time-seconds time))))

(defun time-function (func &rest args)
  "Return the time in seconds taken to execute FUNC with ARGS.
Returned is actually the cons pair (func-value . time)."
  (garbage-collect)
  (let ((start (time-seconds)))
    (cons (apply func args) (time-since start))))

(defun time-regexps (regexps &optional buffer unfontify)
  "Return corresponding list of times to fontify using REGEXPS.
Fontify using BUFFER, if non-nil, and UNFONTIFY first, if non-nil."
  (save-excursion
    (and buffer (set-buffer buffer))
    (let ((beg (point-min)) (end (point-max)))
      (and unfontify (font-lock-unfontify-region beg end))
      (mapcar (function (lambda (regexp)
	       (let ((font-lock-keywords (list regexp)))
		 (cons (cdr (time-function 'font-lock-hack-keywords beg end))
		       regexp))))
	      regexps))))

(defun sort-font-lock-regexps (regexps &optional buffer unfontify)
  "Return sorted times to fontify syntactically and using REGEXPS.
UNFONTIFY first, if non-nil."
  (let ((regexp-time (time-regexps regexps buffer unfontify)))
    (cons (list (apply '+ (mapcar 'car regexp-time)) 'regexps)
          (nreverse (sort regexp-time 'car-less-than-car)))))

(defun time-fontification (&optional buffer unfontify)
  "Return time to fontify syntactically.
UNFONTIFY first, if non-nil."
  (save-excursion
    (and buffer (set-buffer buffer))
    (let ((beg (point-min)) (end (point-max)))
      (and unfontify (font-lock-unfontify-region beg end))
      (cdr (time-function 'font-lock-fontify-region beg end)))))

(defun sort-font-lock-fontification (regexps &optional buffer unfontify)
  "Return sorted times to fontify syntactically and using REGEXPS.
UNFONTIFY first, if non-nil."
  (let ((syntactic-time (time-fontification buffer unfontify))
	(regexp-time (time-regexps regexps buffer)))
    (nreverse
     (sort (append (list (list syntactic-time 'syntactic)
			 (list (apply '+ (mapcar 'car regexp-time)) 'regexps))
		   regexp-time)
	   'car-less-than-car))))

;;; make-regexp.el ends here
tdtd/tdtd-font.el0100444000076500007650000002720506676775260014104 0ustar  camillecamille;;;; tdtd-font.el --- Font-lock keywords for Tony's DTD mode
;; $Id: tdtd-font.el,v 1.3 1999/03/23 13:07:29 tkg Exp $
;; $Name: tdtd071 $
;;
;; Copyright (C) 1999, Tony Graham
;;
;; Author: Tony Graham <tgraham@mulberrytech.com>

;;; This file is not part of GNU Emacs.

;; 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
;; of the License, 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; if not, write to the Free Software
;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

;; Generated by tdtd-font-maker.el
;; Do not modify this file.  Make changes in tdtd-font-maker.el
;; and regenerate.

;; Send bugs to tdtd-bug@menteith.com


(defvar dtd-sgml-font-lock-keywords
  '(("<!--[^-]*\\(-[^-]+\\)*-->" . font-lock-comment-face) ("--[^-]*\\(-[^-]+\\)*--" . font-lock-comment-face) ("<!--[^-]*\\(-[^-]+\\)*-->" . font-lock-comment-face) ("[%&][^; \t]+;" . font-lock-reference-face) ("\\(<!\\(ATTLIST\\|ENTITY\\(\\s-+%\\|\\)\\|NOTATION\\)\\)\\s-+\\(\\S-+\\)[^>]+\\(>\\)" (1 font-lock-keyword-face) (4 font-lock-variable-name-face) (5 font-lock-keyword-face)) ("\\(<!DOCTYPE\\)\\s-+\\([^[]+\\)\\s-+\\(\\[\\)" (1 font-lock-keyword-face) (2 font-lock-variable-name-face) (3 font-lock-keyword-face)) ("\\(<!ELEMENT\\)\\s-+\\([^ \t()|]+\\)\\s-+[^>]+\\(>\\)" (1 font-lock-keyword-face) (2 font-lock-variable-name-face) (3 font-lock-keyword-face)) ("\\(<!\\[\\)[^[]*\\(\\[\\)" (1 font-lock-keyword-face) (2 font-lock-keyword-face)) ("\\(<!\\(SHORTREF\\|USEMAP\\)\\)\\s-+\\(\\S-+\\)[^>]+\\(>\\)" (1 font-lock-keyword-face) (3 font-lock-variable-name-face) (4 font-lock-keyword-face)) ("\\(<!ELEMENT\\)\\s-+\\([^ \t()|]+\\)\\s-+\\(o\\s-+o\\|O\\s-+O\\|-\\s-+[oO]\\|[oO]\\s-+-\\)\\s-+[^>]+\\(>\\)" (1 font-lock-keyword-face) (2 font-lock-variable-name-face) (3 font-lock-keyword-face) (4 font-lock-keyword-face)) ("\\(\\(-\\|+\\)(\\)[^)]*\\()\\)" (1 font-lock-variable-name-face) (3 font-lock-variable-name-face)) ("\\(<!LINKTYPE\\)\\s-+\\([^ \t]+\\)\\s-+\\([^ \t]+\\)\\s-+\\(\\#IMPLIED\\)[ \t\n]*\\(\\[\\)" (1 font-lock-keyword-face) (2 font-lock-variable-name-face) (3 font-lock-variable-name-face) (4 font-lock-keyword-face) (5 font-lock-keyword-face)) ("\\(<!LINKTYPE\\)\\s-+\\([^ \t]+\\)\\s-+\\([^ \t]+\\)\\s-+\\([^ \t]+\\)\\s-*\\(\\[\\)" (1 font-lock-keyword-face) (2 font-lock-variable-name-face) (3 font-lock-variable-name-face) (4 font-lock-type-face) (5 font-lock-keyword-face)) ("\\(<!IDLINK\\)\\b[^>]+\\(>\\)" (1 font-lock-keyword-face) (2 font-lock-keyword-face)) ("\\(<\\?\\)\\([^ \t>]+\\)\\s-*[^>]*\\(>\\)" (1 font-lock-keyword-face) (2 font-lock-variable-name-face) (3 font-lock-keyword-face)) ("\\(#\\(ALL\\|C\\(ONREF\\|URRENT\\)\\|DEFAULT\\|FIXED\\|I\\(MPLI\\(CIT\\|ED\\)\\|NITIAL\\)\\|NOTATION\\|P\\(CDATA\\|OSTLINK\\)\\|RE\\(QUIRED\\|STORE\\)\\|SIMPLE\\|USELINK\\)\\|+//\\(\\|IDN\\)\\|-//\\|//\\)\\b" (1 font-lock-type-face)) ("\\b\\(A\\(NY\\|TTLIST\\)\\|CDATA\\|D\\(ATA\\|OCTYPE\\|TD\\)\\|E\\(LEMENT\\|MPTY\\|NTIT\\(IES\\|Y\\)\\|XPLICIT\\)\\|I\\(D\\(\\|LINK\\|REFS?\\)\\|MPLICIT\\)\\|LINK\\(\\|TYPE\\)\\|N\\(AME\\(\\|CHAR\\|S\\)\\|DATA\\|MTOKENS?\\|OTATION\\|U\\(MBERS?\\|TOKENS?\\)\\)\\|P\\(OSTLINK\\|UBLIC\\)\\|RCDATA\\|S\\(DATA\\|HORTREF\\|IMPLE\\|UBDOC\\|YSTEM\\)\\|TEMP\\|USE\\(LINK\\|MAP\\)\\)\\b" (1 font-lock-type-face)) ("\\(\\]?\\]\\)\\s-*\\(>\\)" (1 font-lock-keyword-face) (2 font-lock-keyword-face)) ("\\('\\)[^']*\\('\\)" (1 font-lock-string-face) (2 font-lock-string-face)) ("\\(\"\\)[^\"]*\\(\"\\)" (1 font-lock-string-face) (2 font-lock-string-face)) ("[,()|&]" . font-lock-function-name-face) ("[+*?]" . font-lock-string-face)))

(defvar dtd-xml-font-lock-keywords
  '(("<!--[^-]*\\(-[^-]+\\)*-->" . font-lock-comment-face) ("[%&][^; \t]+;" . font-lock-reference-face) ("\\(<!\\(ATTLIST\\|ENTITY\\(\\s-+%\\|\\)\\|NOTATION\\)\\)\\s-+\\(\\S-+\\)[^>]+\\(>\\)" (1 font-lock-keyword-face) (4 font-lock-variable-name-face) (5 font-lock-keyword-face)) ("\\(<!DOCTYPE\\)\\s-+\\([^[]+\\)\\s-+\\(\\[\\)" (1 font-lock-keyword-face) (2 font-lock-variable-name-face) (3 font-lock-keyword-face)) ("\\(<!ELEMENT\\)\\s-+\\([^ \t()|]+\\)\\s-+[^>]+\\(>\\)" (1 font-lock-keyword-face) (2 font-lock-variable-name-face) (3 font-lock-keyword-face)) ("\\(<!\\[\\)[^[]*\\(\\[\\)" (1 font-lock-keyword-face) (2 font-lock-keyword-face)) ("\\(<\\?\\)\\(xml\\)\\(\\s-+version\\s-*=\\s-*\\('[^']+'\\|\"[^\"]+\"\\)\\)?\\(\\s-+encoding\\s-*=\\s-*\\('[^']+'\\|\"[^\"]+\"\\)\\)?\\(\\s-+standalone\\s-*=\\s-*\\('\\(yes\\|no\\)'\\|\"\\(yes\\|no\\)\"\\)\\)?\\s-*\\(\\?>\\)" (1 font-lock-keyword-face) (2 font-lock-type-face nil) (3 font-lock-type-face nil t) (5 font-lock-type-face nil t) (7 font-lock-type-face nil t) (11 font-lock-keyword-face)) ("\\(<\\?\\)\\([^ \t?>]+\\)\\s-*\\([^?>]\\|\\?[^>]\\|>[^\n\r]\\)*\\(\\?>\\)" (1 font-lock-keyword-face) (2 font-lock-variable-name-face) (4 font-lock-keyword-face)) ("\\(#\\(DEFAULT\\|FIXED\\|IMPLIED\\|NOTATION\\|PCDATA\\|REQUIRED\\)\\|+//\\(\\|IDN\\)\\|-//\\|//\\)\\b" (1 font-lock-type-face)) ("\\b\\(xml:\\(l\\(ang\\|ink\\)\\|space\\)\\)\\b" (1 font-lock-type-face)) ("\\b\\(A\\(NY\\|TTLIST\\)\\|C\\(APACITY\\|DATA\\|HARSET\\)\\|D\\(OC\\(TYPE\\|UMENT\\)\\|TD\\)\\|E\\(LEMENTS?\\|MPTY\\|NTIT\\(IES\\|Y\\)\\)\\|ID\\(\\|REFS?\\)\\|LPD\\|N\\(DATA\\|MTOKENS?\\|O\\(NSGML\\|TATION\\)\\|UTOKENS?\\)\\|PUBLIC\\|S\\(HORTREF\\|UBDOC\\|Y\\(NTAX\\|STEM\\)\\)\\|TEXT\\|XML\\|xml\\)\\b" (1 font-lock-type-face)) ("\\(\\]?\\]\\)\\s-*\\(>\\)" (1 font-lock-keyword-face) (2 font-lock-keyword-face)) ("\\('\\)[^']*\\('\\)" (1 font-lock-string-face) (2 font-lock-string-face)) ("\\(\"\\)[^\"]*\\(\"\\)" (1 font-lock-string-face) (2 font-lock-string-face)) ("[,()|&]" . font-lock-function-name-face) ("[+*?]" . font-lock-string-face)))

(defvar dtd-decl-font-lock-keywords
  '(("--[^-]*\\(-[^-]+\\)*--" . font-lock-comment-face) ("<!--[^-]*\\(-[^-]+\\)*-->" . font-lock-comment-face) ("[%&][^; \t]+;" . font-lock-reference-face) ("\\(<!\\(ATTLIST\\|ENTITY\\(\\s-+%\\|\\)\\|NOTATION\\)\\)\\s-+\\(\\S-+\\)[^>]+\\(>\\)" (1 font-lock-keyword-face) (4 font-lock-variable-name-face) (5 font-lock-keyword-face)) ("\\(<!DOCTYPE\\)\\s-+\\([^[]+\\)\\s-+\\(\\[\\)" (1 font-lock-keyword-face) (2 font-lock-variable-name-face) (3 font-lock-keyword-face)) ("\\(<!ELEMENT\\)\\s-+\\([^ \t()|]+\\)\\s-+[^>]+\\(>\\)" (1 font-lock-keyword-face) (2 font-lock-variable-name-face) (3 font-lock-keyword-face)) ("\\(<!\\[\\)[^[]*\\(\\[\\)" (1 font-lock-keyword-face) (2 font-lock-keyword-face)) ("\\(<!SGML\\)\\s-+\\([^>]\\|>[^$]\\)+\\(>$\\)" (1 font-lock-keyword-face) (3 font-lock-keyword-face)) ("\\b\\(A\\(LL\\|N[DY]\\|PPINFO\\|TT\\(C\\(AP\\|HCAP\\|NT\\)\\|LIST\\|RIB\\|SPLEN\\)\\|VGRPCAP\\)\\|B\\(ASESET\\|B\\|SEQLEN\\)\\|C\\(APACITY\\|DATA\\|HARSET\\|O\\(M\\|N\\(CUR\\|REF\\|TROLS\\)\\)\\|RO\\|URRENT\\)\\|D\\(ATATAG\\|E\\(FAULT\\|LIM\\|SCSET\\)\\|OC\\(TYPE\\|UMENT\\)\\|S[CO]\\|T\\(AGLEN\\|D\\|EMPLEN\\|G[CO]\\)\\)\\|E\\(LEM\\(CAP\\|ENTS?\\)\\|MPTY\\(\\|NRM\\)\\|N\\(DTAG\\|T\\(C\\(AP\\|HCAP\\)\\|IT\\(IES\\|Y\\)\\|LVL\\)\\)\\|RO\\|TAGO\\|X\\(GRPCAP\\|NMCAP\\|PLICIT\\)\\)\\|F\\(EATURES\\|IXED\\|ORMAL\\|UNC\\(HAR\\|TION\\)\\)\\|G\\(ENERAL\\|RP\\([CO]\\|C\\(AP\\|NT\\)\\|GTCNT\\|LVL\\)\\)\\|HCRO\\|I\\(D\\(\\|CAP\\|LINK\\|REF\\(\\|CAP\\|S\\)\\)\\|GNORE\\|M\\(MEDNET\\|PL\\(I\\(CIT\\|ED\\)\\|YDEF\\)\\)\\|N\\(CLUDE\\|ITIAL\\|STANCE\\|TE\\(GRAL\\|RNAL\\)\\)\\)\\|KEEPRSRE\\|L\\(CNM\\(CHAR\\|STRT\\)\\|I\\(NK\\(\\|TYPE\\)\\|T\\(\\|A\\|LEN\\)\\)\\|K\\(NMCAP\\|SETCAP\\)\\|PD\\)\\|M\\([DS]\\|APCAP\\|D[CO]\\|IN\\(IMIZE\\|US\\)\\|S\\(C\\|ICHAR\\|OCHAR\\|SCHAR\\)\\)\\|N\\(AM\\(E\\(\\|C\\(ASE\\|HAR\\)\\|LEN\\|S\\(\\|TRT\\)\\)\\|ING\\)\\|DATA\\|E\\(STC\\|T\\(\\|ENABL\\)\\)\\|MTOKENS?\\|O\\(\\|ASSERT\\|N\\(E\\|SGML\\)\\|RMSEP\\|T\\(ATION\\|C\\(AP\\|HCAP\\)\\)\\)\\|U\\(MBERS?\\|TOKENS?\\)\\)\\|O\\(\\|MIT\\(NAME\\|TAG\\)\\|PT\\|R\\|THER\\)\\|P\\(CDATA\\|ERO\\|I\\(\\|[CO]\\|LEN\\)\\|LUS\\|OSTLINK\\|UBLIC\\)\\|QUANTITY\\|R\\([ES]\\|ANK\\|CDATA\\|E\\([FP]\\|FC\\|QUIRED\\|STORE\\)\\|NI\\)\\|S\\(COPE\\|DATA\\|E\\(EALSO\\|PCHAR\\|Q\\)\\|GMLREF\\|H\\(ORT\\(REF\\|TAG\\)\\|UNCHAR\\)\\|IMPLE\\|PACE\\|TA\\(GO\\|RTTAG\\)\\|UBDOC\\|WITCHES\\|Y\\(NTAX\\|STEM\\)\\)\\|T\\(A\\(B\\|G\\(C\\|L\\(EN\\|VL\\)\\)\\)\\|E\\(MP\\|XT\\)\\|OTALCAP\\|YPE\\)\\|U\\(CNM\\(CHAR\\|STRT\\)\\|N\\(CLOSED\\|USED\\)\\|RN\\|SE\\(LINK\\|MAP\\)\\)\\|V\\(AL\\(IDITY\\|UE\\)\\|I\\)\\|YES\\)\\b" (1 font-lock-type-face)) ("\\(ISO 8879\\(-1986\\|:1986\\(\\|(\\(ENR)\\|WWW)\\)\\)\\)\\)" (1 font-lock-type-face)) ("\\(-//\\|//\\)\\b" (1 font-lock-type-face)) ("\\(\\]?\\]\\)\\s-*\\(>\\)" (1 font-lock-keyword-face) (2 font-lock-keyword-face)) ("\\('\\)[^']*\\('\\)" (1 font-lock-string-face) (2 font-lock-string-face)) ("\\(\"\\)[^\"]*\\(\"\\)" (1 font-lock-string-face) (2 font-lock-string-face)) ("[,()|&]" . font-lock-function-name-face) ("[+*?]" . font-lock-string-face)))

(defvar dtd-sys-decl-font-lock-keywords
  '(("--[^-]*\\(-[^-]+\\)*--" . font-lock-comment-face) ("[%&][^; \t]+;" . font-lock-reference-face) ("\\(<!SYSTEM\\)\\([^>]\\|>[^$]\\)+\\(>$\\)" (1 font-lock-keyword-face) (3 font-lock-keyword-face)) ("\\(+//\\(\\|IDN\\)\\|-//\\|//\\)\\b" (1 font-lock-type-face)) ("\\b\\(A\\(LL\\|N[DY]\\|SN1\\|TT\\(C\\(AP\\|HCAP\\|NT\\)\\|LIST\\|RIB\\|SPLEN\\)\\|VGRPCAP\\)\\|B\\(ASESET\\|B\\|SEQLEN\\)\\|C\\(APACITY\\|DATA\\|HA\\(NGES\\|RSET\\)\\|O\\(M\\|N\\(CUR\\|REF\\|TROLS\\)\\)\\|RO\\|URRENT\\)\\|D\\(ATATAG\\|E\\(FAULT\\|LIM\\(\\|LEN\\)\\|SCSET\\)\\|OC\\(TYPE\\|UMENT\\)\\|S[CO]\\|T\\(AGLEN\\|D\\|EMPLEN\\|G[CO]\\)\\)\\|E\\(LEM\\(CAP\\|ENTS?\\)\\|MPTY\\(\\|NRM\\)\\|N\\(DTAG\\|T\\(C\\(AP\\|HCAP\\)\\|IT\\(IES\\|Y\\)\\|LVL\\)\\)\\|RO\\|TAGO\\|X\\(CLUDE\\|GRPCAP\\|NMCAP\\|PLICIT\\)\\)\\|F\\(EATURES\\|IXED\\|ORMAL\\|UNC\\(HAR\\|TION\\)\\)\\|G\\(ENERAL\\|RP\\([CO]\\|C\\(AP\\|NT\\)\\|GTCNT\\|LVL\\)\\)\\|HCRO\\|I\\(D\\(\\|CAP\\|LINK\\|REF\\(\\|CAP\\|S\\)\\)\\|GNORE\\|M\\(MEDNET\\|PL\\(I\\(CIT\\|ED\\)\\|YDEF\\)\\)\\|N\\(CLUDE\\|ITIAL\\|STANCE\\|TE\\(GRAL\\|RNAL\\)\\)\\)\\|KEEPRSRE\\|L\\(CNM\\(CHAR\\|STRT\\)\\|I\\(NK\\(\\|TYPE\\)\\|T\\(\\|A\\|LEN\\)\\)\\|K\\(NMCAP\\|SETCAP\\)\\|PD\\)\\|M\\([DS]\\|APCAP\\|D[CO]\\|IN\\(IMIZE\\|US\\)\\|ODEL\\|S\\(C\\|ICHAR\\|OCHAR\\|SCHAR\\)\\)\\|N\\(AM\\(E\\(\\|C\\(ASE\\|HAR\\)\\|LEN\\|S\\(\\|TRT\\)\\)\\|ING\\)\\|DATA\\|E\\(STC\\|T\\(\\|ENABL\\)\\)\\|MTOKENS?\\|O\\(\\|ASSERT\\|N\\(E\\|SGML\\)\\|RMSEP\\|T\\(ATION\\|C\\(AP\\|HCAP\\)\\)\\)\\|U\\(MBERS?\\|TOKENS?\\)\\)\\|O\\(\\|MIT\\(NAME\\|TAG\\)\\|PT\\|R\\|THER\\)\\|P\\(ACK\\|CDATA\\|ERO\\|I\\(\\|[CO]\\|LEN\\)\\|LUS\\|OSTLINK\\|UBLIC\\)\\|QUANTITY\\|R\\([ES]\\|ANK\\|CDATA\\|E\\([FP]\\|FC\\|QUIRED\\|STORE\\)\\|NI\\)\\|S\\(COPE\\|D\\(ATA\\|IF\\)\\|E\\(EALSO\\|PCHAR\\|Q\\(\\|UENCE\\)\\)\\|GML\\(\\|REF\\)\\|H\\(ORT\\(REF\\|TAG\\)\\|UNCHAR\\)\\|IMPLE\\|PACE\\|R\\(CNT\\|LEN\\)\\|TA\\(GO\\|RTTAG\\)\\|UBDOC\\|WITC\\(ES\\|HES\\)\\|Y\\(NTAX\\|STEM\\)\\)\\|T\\(A\\(B\\|G\\(C\\|L\\(EN\\|VL\\)\\)\\)\\|E\\(MP\\|XT\\)\\|OTALCAP\\|YPE\\)\\|U\\(CNM\\(CHAR\\|STRT\\)\\|N\\(CLOSED\\|PACK\\|USED\\)\\|RN\\|SE\\(LINK\\|MAP\\)\\)\\|V\\(AL\\(ID\\(ATE\\|ITY\\)\\|UE\\)\\|I\\)\\|YES\\)\\b" (1 font-lock-type-face)) ("\\(ISO 8879:1986\\(\\|(\\(ENR)\\|WWW)\\)\\)\\)" (1 font-lock-type-face)) ("\\(\\]?\\]\\)\\s-*\\(>\\)" (1 font-lock-keyword-face) (2 font-lock-keyword-face)) ("\\('\\)[^']*\\('\\)" (1 font-lock-string-face) (2 font-lock-string-face)) ("\\(\"\\)[^\"]*\\(\"\\)" (1 font-lock-string-face) (2 font-lock-string-face)) ("[,()|&]" . font-lock-function-name-face) ("[+*?]" . font-lock-string-face)))

(provide 'tdtd-font)
tdtd/tdtd-font-maker.el0100444000076500007650000007016506676775260015204 0ustar  camillecamille;;;; tdtd-font-maker.el --- Specify and generate font-lock keywords
;; $Id: tdtd-font-maker.el,v 0.18 1999/03/25 23:17:24 tkg Exp $
;; $Name: tdtd071 $

;; Copyright (C) 1997, 1998, 1999 Tony Graham

;; Author: Tony Graham <tgraham@mulberrytech.com>

;;; This file is not part of GNU Emacs.

;; 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
;; of the License, 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; if not, write to the Free Software
;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.


;;;; Commentary:

;; `dtd-make-tdtd-font' in this file writes the tdtd-font.el file that
;; contains the font-lock keywords for DTD mode.  The convoluted logic
;; for the regular expressions for the font lock mode keywords for use
;; when editing DTDs are contained in this file.  Changes to the DTD
;; mode font-lock keywords should be made in this file and a new
;; tdtd-font.el regenerated instead of changing tdtd-font.el directly
;; (and if you've looked in tdtd-font.el, you'll know why).

;; Use `dtd-submit-bug-report' to report bugs.

;; The font lock keywords are complicated firstly by the need to match
;; declaration formats and reserved names in XML DTDs, SGML DTDs, SGML
;; Declarations, and SGML System Declarations, and secondly because we
;; match on both complete declarations and reserved names such that
;; the reserved names change colour as they are entered, then some or
;; all of the declaration changes colour again when the closing
;; delimiter is entered.  This makes the keywords more complicated,
;; but it provides visual feedback that a declaration is complete.

;; Reserved words in SGML, XML, and SGML Declarations
;;
;; Meaning of the columns:
;; XML -- Allowed in XML DTDs
;; SGML -- Allowed in SGML DTDs and LPDs
;; Decl -- Allowed in SGML Declarations
;; System -- Allowed in System Declarations
;;
;; Note that the font lock keywords for an SGML Declaration includes
;; both the keywords identified as allowed in SGML Declarations and
;; the keywords identified as allowed in SGML DTDs and LPDs since the
;; SGML Declaration may be followed by a DTD or DTDs and LPD or LPDs.
;;
;; In several cases, keywords beginning with "#" (RNI) are shown as
;; allowed in XML and SGML DTDs, and the word without the RNI is shown
;; as allowed in SGML Declarations.  SGML's reserved words that are
;; not used in the SGML Declaration may be redefined in the
;; Declaration, hence the non-RNI form is a keyword in the Declaration
;; (even though this font lock stuff doesn't match on the redefined
;; reserved word).
;;
;;
;;  Word		XML	SGML    Decl 	System
;;  -//			x	x	x	x
;;  +//			x	x	x	x
;;  +//IDN		x	x	x	x
;;  //			x	x	x	x
;;  #ALL			x
;;  #CONREF			x
;;  #CURRENT			x
;;  #DEFAULT			x
;;  #EMPTY			x	
;;  #FIXED		x       x
;;  #IMPLICIT			x
;;  #IMPLIED		x       x
;;  #INITIAL			x 	
;;  #NOTATION			x
;;  #PCDATA		x       x
;;  #POSTLINK			x
;;  #REQUIRED		x       x
;;  #RESTORE			x
;;  #SIMPLE			x
;;  #USELINK			x
;;  ALL					x	x
;;  AND					x	x
;;  ANY			x	x	x	x
;;  APPINFO				x
;;  ASN1					x
;;  ATTCAP				x	x
;;  ATTCHCAP				x	x
;;  ATTCNT				x	x
;;  ATTLIST		x	x	x	x
;;  ATTRIB				x	x
;;  ATTSPLEN				x	x
;;  AVGRPCAP				x	x
;;  BASESET				x	x
;;  BB					x	x
;;  BSEQLEN				x	x
;;  CAPACITY				x	x
;;  CDATA		x	x	x	x
;;  CHANGES				x	x
;;  CHARSET				x	x
;;  COM					x	x
;;  CONCUR			 	x
;;  CONREF			x	x	x
;;  CONTROLS				x	x
;;  CRO					x	x
;;  CURRENT			x	x	x
;;  DATA			x	x	x
;;  DATATAG				x	x
;;  DEFAULT			x	x	x
;;  DELIMLEN					x
;;  DELIM				x	x
;;  DESCSET				x	x
;;  DOCTYPE		x	x	x	x
;;  DOCUMENT				x	x
;;  DSC					x	x
;;  DSO					x	x
;;  DTAGLEN				x	x
;;  DTD				x       x
;;  DTEMPLEN				x	x
;;  DTGC				x	x
;;  DTGO				x	x
;;  ELEMCAP				x
;;  ELEMENT		x	x	x	x
;;  EMPTY		x	x	x	x
;;  EMPTYNRM				x	x
;;  ENDTAG			x	x	x
;;  ENTITIES		x	x	x	x
;;  ENTITY		x	x	x	x
;;  ENTLVL				x	x
;;  ENTCAP				x	x
;;  ENTCHCAP				x	x
;;  ERO					x	x
;;  ETAGO				x	x
;;  EXCLUDE					x
;;  EXGRPCAP				x	x
;;  EXNMCAP				x	x
;;  EXPLICIT				x
;;  FEATURES				x	x
;;  FIXED				x	x
;;  FORMAL				x	x
;;  FUNCHAR				x	x
;;  FUNCTION				x	x
;;  GENERAL				x	x
;;  GRPC				x	x
;;  GRPCNT				x	x
;;  GRPGTCNT				x	x
;;  GRPLVL				x	x
;;  GRPO				x	x
;;  HCRO				x	x
;;  ID			x	x       x	x
;;  IDCAP				x	x
;;  IDLINK			x	x	x
;;  IDREF		x	x	x	x
;;  IDREFCAP				x	x
;;  IDREFS		x	x	x	x
;;  IGNORE			x	x	x
;;  IMPLIED				x	x
;;  IMPLICIT				x	x
;;  IMPLYDEF				x	x
;;  INCLUDE			x	x	x
;;  INITIAL				x	x
;;  INSTANCE				x	x
;;  INTEGRAL				x	x
;;  INTERNAL				x	x
;;  ISO 8879-1986			x	x
;;  ISO 8879:1986			x	x
;;  KEEPRSRE				x	x
;;  LCNMCHAR				x	x
;;  LCNMSTRT				x	x
;;  LINK				x	x
;;  LINKTYPE				x	x
;;  LIT					x	x
;;  LITA				x	x
;;  LITLEN				x	x
;;  LKNMCAP				x	x
;;  LKSETCAP				x	x
;;  MAPCAP				x	x
;;  MD					x	x
;;  MDC					x	x
;;  MDO					x	x
;;  MINIMIZE				x
;;  MINUS				x	x
;;  MODEL					x
;;  MSICHAR				x
;;  MSOCHAR				x
;;  MSSCHAR				x
;;  MS					x	x
;;  MSC					x	x
;;  NAME	  	  	x	x	x
;;  NAMECASE				x	x
;;  NAMECHAR				x	x
;;  NAMELEN				x	x
;;  NAMES			x	x	x
;;  NAMESTRT				x	x
;;  NAMING				x	x
;;  NDATA		x	x	x	x
;;  NET					x	x
;;  NESTC				x	x
;;  NETENABL				x	x
;;  NMTOKEN		x	x	x	x
;;  NMTOKENS		x	x	x	x
;;  NOASSERT				x	x
;;  NONE				x	x
;;  NONSGML			x	x	x
;;  NORMSEP				x	x
;;  NOTATION		x	x	x	x
;;  NO					x	x
;;  NOTCAP				x	x
;;  NOTCHCAP				x	x
;;  NUMBER			x       x	x
;;  NUMBERS			x	x	x
;;  NUTOKEN			x	x	x
;;  NUTOKENS			x	x	x
;;  O					x	x
;;  OMITNAME				x	x
;;  OMITTAG				x
;;  OPT					x	x
;;  OR					x	x
;;  OTHER				x
;;  PACK					x
;;  PCDATA		x	x	x	x
;;  PERO				x	x
;;  PI				x	x	x
;;  PIC					x	x
;;  PILEN				x	x
;;  PIO					x	x
;;  PLUS				x	x
;;  POSTLINK				x	x
;;  PUBLIC		x	x	x	x
;;  QUANTITY				x	x
;;  RANK				x	x
;;  RCDATA			x	x	x
;;  RE				x	x	x
;;  REF					x	x
;;  REFC				x	x
;;  REP					x	x
;;  REQUIRED				x	x
;;  RESTORE				x	x
;;  RNI					x	x
;;  RS				x	x	x
;;  SCOPE				x
;;  SDATA			x	x	x
;;  SDIF					x
;;  SEEALSO				x	x
;;  SEPCHAR				x
;;  SEQ					x	x
;;  SEQUENCE				x
;;  SGML				x	x
;;  SGMLREF				x       x
;;  SHORTREF			x	x	x
;;  SHORTTAG				x	x
;;  SHUNCHAR				x	x
;;  SIMPLE				x	x
;;  SPACE				x	x
;;  SRCNT				x	x
;;  SRLEN				x	x
;;  STAGO				x	x
;;  STARTTAG			x	x	x
;;  SUBDOC			x	x	x
;;  SWITCHES				x	x
;;  SYNTAX				x	x
;;  SYSTEM		x	x	x	x
;;  TEMP			x	x	x
;;  TAGC				x	x
;;  TAGLEN				x	x
;;  TAGLVL				x	x
;;  TAB					x	x
;;  TOTALCAP				x	x
;;  TYPE				x	x
;;  UCNMCHAR				x       x
;;  UCNMSTRT				x	x
;;  UNCLOSED				x	x
;;  UNPACK					x
;;  UNUSED				x	x
;;  URN					x	x
;;  USELINK			x	x	x
;;  USEMAP			x	x	x
;;  VALIDATE					x
;;  VALIDITY				x	x
;;  VALUE				x	x
;;  VI					x	x
;;  XML			x
;;  xml			x
;;  xml:lang		x
;;  xml:link		x
;;  xml:space		x
;;  YES					x	x

;;;; Code:
(eval-and-compile
  (autoload 'make-regexp "make-regexp"))
(eval-and-compile
  (autoload 'make-regexps "make-regexp"))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Lists of reserved names
;;
;; These lists of reserved names are used later in the declarations
;; for parts of font lock keyword variables or in the declarations for
;; complete font lock keywords.
;;
;; The XML and SGML keyword lists are kept separate, despite their
;; overlap, for two reasons: (1) making extra variables to hold the
;; lists of common keywords would complicate things beyond even the
;; current level; and (2) XML may yet change its reserved names or add
;; new ones.
;;
;; The lists of reserved names are further divided into those that
;; begin with an Emacs-Lisp non-word character, those that contain a
;; non-word character, and those that don't contain any non-word
;; characters.  This is necessary since the keyword regular
;; expressions are bracketed by "\\b", which is necessary so the
;; regular expressions produced by `make-regexps' match on the longest
;; possible string.  I have previously tried producing font lock
;; keywords regular expressions for these reserved names by hand, but
;; they're not particularly readable or maintainable when done by
;; hand.
;;
;; There are several lists of reserved names for portions of SGML
;; Declarations and System Declarations.  This reflects the
;; productions and tables in the SGML standard, and it makes it easier
;; to keep track of why everything is included.

;; Common reserved name lists

(defconst dtd-public-text-class-keywords
  (list
   "CAPACITY" "CHARSET" "DOCUMENT" "DTD" "ELEMENTS" "ENTITIES" "LPD"
   "NONSGML" "NOTATION" "SHORTREF" "SUBDOC" "SYNTAX" "TEXT")
  "Reserved names for Public Text Class in a Formal Public Identifier.")

;; XML DTD reserved name lists

(defconst dtd-xml-keyword-list-1
  (list
   "-//" "\+//" "//" "\+//IDN"
   "#DEFAULT" "#FIXED" "#IMPLIED" "#NOTATION"
   "#PCDATA" "#REQUIRED"
   )
  "XML reserved names strings that don't start with word character.")

(defconst dtd-xml-keyword-list-2
  (list
   "xml:lang" "xml:link" "xml:space"
   )
  "XML reserved names containing non-word characters.")

(defconst dtd-xml-keyword-list-3
  (append
   dtd-public-text-class-keywords
   (list
    "ANY" "ATTLIST" "CDATA" "DOCTYPE" "DTD"
    "ELEMENT" "EMPTY" "ENTITIES" "ENTITY" "ID" "IDREF" "IDREFS"
    "NDATA" "NMTOKEN" "NMTOKENS" "NOTATION" "NUTOKEN" "NUTOKENS"
    "PUBLIC" "SYSTEM" "XML" "xml"
    )
   )
  "Reserved names significant in XML.")

;; SGML DTD reserved name lists

(defconst dtd-sgml-keyword-list-1
  (list
   "-//" "\+//" "//" "\+//IDN"
   "#ALL" "#CONREF" "#CURRENT" "#DEFAULT"
   "#FIXED" "#IMPLICIT" "#IMPLIED" "#INITIAL" "#NOTATION" "#PCDATA"
   "#POSTLINK" "#REQUIRED" "#RESTORE" "#SIMPLE" "#USELINK"
   )
  "SGML reserved names and strings beginning with a non-word character.")


(defconst dtd-sgml-keyword-list-2
  (list
   "ANY" "ATTLIST" "CDATA" "DATA" "DOCTYPE" "DTD" "ELEMENT" "EMPTY"
   "ENTITIES" "ENTITY" "EXPLICIT" "ID" "IDLINK" "IDREF" "IDREFS"
   "IMPLICIT" "LINKTYPE" "LINK" "NAME" "NAMECHAR" "NAMES" "NDATA"
   "NMTOKEN" "NMTOKENS" "NOTATION" "NUMBER" "NUMBERS" "NUTOKEN"
   "NUTOKENS" "POSTLINK" "PUBLIC" "RCDATA" "SDATA" "SHORTREF" "SIMPLE"
   "SUBDOC" "SYSTEM" "TEMP" "USELINK" "USEMAP")
  "SGML reserved names that do not contain any non-word characters.")

;; SGML Declaration reserved name lists

(defconst dtd-sgml-declaration-minimum-literal-keywords
  (list
   "ISO 8879:1986" "ISO 8879-1986" "ISO 8879:1986(ENR)"
   "ISO 8879:1986(WWW)")
  "Minimum literals at the start of an SGML Declaration.")

(defconst dtd-delimiter-set-keywords
  (append
   ;; Non-shortref delimiters
   (list
    "AND" "COM" "CRO" "DSC" "DSO" "DTGC" "DTGO" "ERO" "ETAGO" "GRPC"
    "GRPO" "LIT" "LITA" "MDC" "MDO" "MINUS" "MSC" "NET" "OPT" "OR"
    "PERO" "PIC" "PIO" "PLUS" "REFC" "REP" "RNI" "SEQ"
    "STAGO" "TAGC" "VI")
   ;; Alphabetic short reference delimiters
   (list "BB")
   ;; Delimiters added with SGML TC2
   (list "HCRO" "NESTC"))
  "Reserved names for specifying delimiter set, including shortrefs."
  )

(defconst dtd-redefinable-reserved-name-keywords
  (list
   "ALL" "ANY" "ATTLIST" "CDATA" "CONREF" "CURRENT" "DEFAULT"
   "DOCTYPE" "ELEMENT" "EMPTY" "ENDTAG" "ENTITIES" "ENTITY" "FIXED"
   "ID" "IDLINK" "IDREF" "IDREFS" "IGNORE" "IMPLICIT" "IMPLIED"
   "INCLUDE" "INITIAL" "LINK" "LINKTYPE" "MD" "MS" "NAME" "NAMES"
   "NDATA" "NMTOKEN" "NMTOKENS" "NOTATION" "NUMBER" "NUMBERS"
   "NUTOKEN" "NUTOKENS" "O" "PCDATA" "PI" "POSTLINK" "PUBLIC" "RCDATA"
   "RE" "REQUIRED" "RESTORE" "RS" "SDATA" "SHORTREF" "SIMPLE" "SPACE"
   "STARTTAG" "SUBDOC" "SYSTEM" "TEMP" "USELINK" "USEMAP")
  "Reserved names that can be modified in NAMES portion of SGML Declaration.")

(defconst dtd-quantity-set-keywords
  (list
   "ATTCNT" "ATTSPLEN" "BSEQLEN" "DTAGLEN" "DTEMPLEN" "ENTLVL"
   "GRPCNT" "GRPGTCNT" "GRPLVL" "LITLEN" "NAMELEN" "NORMSEP"
   "PILEN" "TAGLEN" "TAGLVL")
  "Reserved names for specifying quantity set.")

(defconst dtd-common-sgml-declaration-keywords
  (list
   "SGMLREF" "PUBLIC" "NONE" "NO" "YES")
  "Reserved names common to multiple parts of an SGML Declaration.")

(defconst dtd-charset-keywords
  (list
   "CHARSET" "BASESET" "DESCSET" "UNUSED")
  "Reserved names used in describing the document character set.")

(defconst dtd-capacity-set-keywords
  (list
   "CAPACITY" "TOTALCAP" "ENTCAP" "ENTCHCAP" "ELEMCAP" "GRPCAP"
   "EXGRPCAP" "EXNMCAP" "ATTCAP" "ATTCHCAP" "AVGRPCAP" "NOTCAP"
   "NOTCHCAP" "IDCAP" "IDREFCAP" "MAPCAP" "LKSETCAP" "LKNMCAP")
  "Reserved names for specifying capacities.")

(defconst dtd-concrete-syntax-scope-keywords
  (list
   "SCOPE" "DOCUMENT" "INSTANCE")
  "Reserved names for specifying concrete syntax scope.")

(defconst dtd-concrete-syntax-keywords
  (append
   (list
    "SYNTAX" "SWITCHES")
   (list
    "SHUNCHAR" "CONTROLS")
   (list
    "FUNCTION" "RE" "RS" "SPACE" "FUNCHAR" "MSICHAR" "MSOCHAR"
    "MSSCHAR" "SEPCHAR" "TAB")
   (list
    "NAMING" "LCNMSTRT" "UCNMSTRT" "NAMESTRT" "LCNMCHAR" "UCNMCHAR"
    "NAMECHAR" "NAMECASE" "GENERAL" "ENTITY")
   (append
    (list
     "DELIM" "GENERAL" "SHORTREF")
    dtd-delimiter-set-keywords)
   (append
    (list
     "NAMES")
    dtd-redefinable-reserved-name-keywords)
   (append
    (list
     "QUANTITY")
    dtd-quantity-set-keywords))
  "Reserved names in specifying a concrete syntax.")

(defconst dtd-features-keywords
  (append
   (list
    "FEATURES" "MINIMIZE" "DATATAG" "OMITTAG" "RANK" "SHORTTAG"
    "LINK" "SIMPLE" "IMPLICIT" "EXPLICIT"
    "OTHER" "CONCUR" "SUBDOC" "FORMAL")
   ;; Reserved names added with SGML TC2
   (list
    "NETENABL" "IMMEDNET" "UNCLOSED" "ATTRIB" "OMITNAME" "VALUE"
    "EMPTYNRM" "IMPLYDEF" "URN" "KEEPRSRE" "VALIDITY" "NOASSERT" "TYPE"
    "REF" "INTERNAL" "INTEGRAL" "SEEALSO"))
  "Reserved names in specifying SGML feature use.")

(defconst dtd-appinfo-keywords
  (list
   "APPINFO")
  "Reserved names in specifying application-specific information.")

;; System Declaration reserved name lists

(defconst dtd-system-declaration-keyword-list-1
  (list
   "-//" "\+//" "//" "\+//IDN")
  "System Declaration reserved names beginning with a non-word character.")

(defconst dtd-concrete-syntax-changes-keywords
  (list
   "CHANGES" "SWITCES" "DELIMLEN" "SEQUENCE" "SRCNT" "SRLEN")
  "Reserved names for concrete syntax changes in System Declaration.")

(defconst dtd-validation-services-keywords
  (list
   "VALIDATE" "GENERAL" "MODEL" "EXCLUDE" "CAPACITY" "NONSGML" "SGML"
   "FORMAL")
  "Reserved names for validation services in System Declaration.")

(defconst dtd-sdif-support-keywords
  (list
   "ASN1" "PACK" "SDIF" "UNPACK")
  "Reserved names for SDIF support in System Declaration.")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reusable portions of keyword variable declarations

;; These are lists of patterns plus face assignments that can be
;; plugged into the definition of the font lock keywords

(defvar dtd-comment-declaration-keywords
  (list
   ;;
   ;; XML comment and one style of SGML comment
   ;;
   ;; SGML-style comments within declarations are covered by
   ;; a separate pattern that is not included in the XML font lock
   ;; keywords.
   ;;
   ;; Put comment patterns first so they mask any declarations
   ;; that might be inside the comment.
   ;;
   '("<!--[^-]*\\(-[^-]+\\)*-->" . font-lock-comment-face)
   )
  "XML comment and one style of SGML comment keywords.")

(defvar dtd-comment-in-declaration-keywords
  (list
   ;;
   ;; SGML-only comment within a declaration
   ;;
   '("--[^-]*\\(-[^-]+\\)*--" . font-lock-comment-face)
   )
  "SGML-only comment within a declaration keywords.")

(defvar dtd-entity-reference-keywords
  (list
   ;;
   ;; Entity references
   ;; These come early so entity references as the names in element, etc.
   ;; declarations retain their colour and don't get turned into
   ;; font-lock-variable-name-face.  E.g:
   ;; <!ENTITY % %entity; "..." >
   ;;
   '("[%&][^; \t]+;" . font-lock-reference-face)
   )
  "Font lock keywords pattern matching an entity reference.")

(defvar dtd-common-font-lock-keywords-1
  (append
   dtd-comment-declaration-keywords
   dtd-entity-reference-keywords
   (list
    ;;
    ;; Lump together attribute, entity, and notation declarations
    ;;
    '("\\(<!\\(ATTLIST\\|ENTITY\\(\\s-+%\\|\\)\\|NOTATION\\)\\)\\s-+\\(\\S-+\\)[^>]+\\(>\\)"
      (1 font-lock-keyword-face)
      (4 font-lock-variable-name-face)
      (5 font-lock-keyword-face))
    ;;
    ;; Doctype declaration
    ;;
    '("\\(<!DOCTYPE\\)\\s-+\\([^[]+\\)\\s-+\\(\\[\\)"
      (1 font-lock-keyword-face)
      (2 font-lock-variable-name-face)
      (3 font-lock-keyword-face))
    ;;
    ;; XML element declaration and SGML element declaration without
    ;; minimisation parameters
    ;;
    '("\\(<!ELEMENT\\)\\s-+\\([^ \t()|]+\\)\\s-+[^>]+\\(>\\)"
      (1 font-lock-keyword-face)
      (2 font-lock-variable-name-face)
      (3 font-lock-keyword-face))
    ;;
    ;; Marked section start
    ;;
    '("\\(<!\\[\\)[^[]*\\(\\[\\)"
      (1 font-lock-keyword-face)
      (2 font-lock-keyword-face))
    )
   )
  "Font lock keyword patterns common to XML and SGML DTDs to apply first.")

(defvar dtd-common-font-lock-keywords-2
  (list
   ;;
   ;; Declaration subset close and markup delimiter close
   ;;
   '("\\(\\]?\\]\\)\\s-*\\(>\\)"
     (1 font-lock-keyword-face)
     (2 font-lock-keyword-face))
   ;;
   ;; Mark the start and end of literals, but don't do anything to their
   ;; contents
   ;;
   '("\\('\\)[^']*\\('\\)"
     (1 font-lock-string-face)
     (2 font-lock-string-face))
   '("\\(\"\\)[^\"]*\\(\"\\)"
     (1 font-lock-string-face)
     (2 font-lock-string-face))
   ;;
   ;; Connectors
   ;;
   '("[,()|&]" . font-lock-function-name-face)
   ;;
   ;; Occurrence indicators
   ;;
   '("[+*?]" . font-lock-string-face)
   ;;
   )
  "Common DTD font lock keyword patterns to apply last.")

(defvar dtd-sgml-dtd-keywords
  (list
   ;;
   ;; Lump together shortref and usemap declarations
   ;;
   '("\\(<!\\(SHORTREF\\|USEMAP\\)\\)\\s-+\\(\\S-+\\)[^>]+\\(>\\)"
	 (1 font-lock-keyword-face)
	 (3 font-lock-variable-name-face)
	 (4 font-lock-keyword-face))
   ;;
   ;; SGML element declaration
   ;;
   ;; Only match on same case of "O", i.e. "o o" or "O O", if both
   ;; start-tag and end-tag are omissible.
   ;;
   '("\\(<!ELEMENT\\)\\s-+\\([^ \t()|]+\\)\\s-+\\(o\\s-+o\\|O\\s-+O\\|-\\s-+[oO]\\|[oO]\\s-+-\\)\\s-+[^>]+\\(>\\)"
	 (1 font-lock-keyword-face)
	 (2 font-lock-variable-name-face)
	 (3 font-lock-keyword-face)
	 (4 font-lock-keyword-face))
   ;;
   ;; Put exclusions in a face that will stand out
   ;;
   '("\\(\\(-\\|+\\)(\\)[^)]*\\()\\)"
     (1 font-lock-variable-name-face)
     (3 font-lock-variable-name-face))
   ;;
   ;; Implicit Link Specification
   ;;
   '("\\(<!LINKTYPE\\)\\s-+\\([^ \t]+\\)\\s-+\\([^ \t]+\\)\\s-+\\(\\#IMPLIED\\)[ \t\n]*\\(\\[\\)"
	 (1 font-lock-keyword-face)
	 (2 font-lock-variable-name-face)
	 (3 font-lock-variable-name-face)
	 (4 font-lock-keyword-face)
	 (5 font-lock-keyword-face))
   ;;
   ;; Explicit Link Specification
   ;;
   '("\\(<!LINKTYPE\\)\\s-+\\([^ \t]+\\)\\s-+\\([^ \t]+\\)\\s-+\\([^ \t]+\\)\\s-*\\(\\[\\)"
	 (1 font-lock-keyword-face)
	 (2 font-lock-variable-name-face)
	 (3 font-lock-variable-name-face)
	 (4 font-lock-type-face)
	 (5 font-lock-keyword-face))
   ;;
   ;; IDLINK link, will appear within an implicit or explicit link
   ;; declaration
   ;;
   '("\\(<!IDLINK\\)\\b[^>]+\\(>\\)"
	 (1 font-lock-keyword-face)
	 (2 font-lock-keyword-face))
   ;;
   ;; SGML Processing instruction
   ;;
   '("\\(<\\?\\)\\([^ \t>]+\\)\\s-*[^>]*\\(>\\)"
     (1 font-lock-keyword-face)
     (2 font-lock-variable-name-face)
     (3 font-lock-keyword-face))
   )
  "Font lock keyword patterns for declarations specific to SGML DTDs.")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Complete font lock keywords variable declarations

;; XML DTDs
(defvar dtd-xml-font-lock-keywords
  (append
   dtd-common-font-lock-keywords-1
   (list
    ;;
    ;; Reserved XML Processing instruction
    ;;
    ;; An 'XML Declaration' requires the version information, but a
    ;; 'Text Declaration' does not, therefore don't require the version
    ;; information.
    '(
      "\\(<\\?\\)\\(xml\\)\\(\\s-+version\\s-*=\\s-*\\('[^']+'\\|\"[^\"]+\"\\)\\)?\\(\\s-+encoding\\s-*=\\s-*\\('[^']+'\\|\"[^\"]+\"\\)\\)?\\(\\s-+standalone\\s-*=\\s-*\\('\\(yes\\|no\\)'\\|\"\\(yes\\|no\\)\"\\)\\)?\\s-*\\(\\?>\\)"
      (1 font-lock-keyword-face)
      (2 font-lock-type-face nil)
      (3 font-lock-type-face nil t)
      (5 font-lock-type-face nil t)
      (7 font-lock-type-face nil t)
      (11 font-lock-keyword-face))
    ;;
    ;; Non-reserved XML Processing instruction
    ;; Any XML PI that doesn't start with "<?xml"
    ;;
    '(
      "\\(<\\?\\)\\([^ \t?>]+\\)\\s-*\\([^?>]\\|\\?[^>]\\|>[^\n\r]\\)*\\(\\?>\\)"
      (1 font-lock-keyword-face)
      (2 font-lock-variable-name-face)
      (4 font-lock-keyword-face))
    ;;
    ;; Keywords starting with a non-word character
    ;;
    (make-regexps
     (list dtd-xml-keyword-list-1
	   font-lock-type-face)
     "\\b")
    ;; Stupidity because I haven't found a better separator than "\\b"
    ;; and the ":" in "xml:link", etc., counts as a "\\b" so "xml:link"
    ;; can't be in the same keyword list as "xml".
    ;;
    ;; The alternative is constructing the regular expression by hand,
    ;; which I've done before, but using `make-regexps' should make more
    ;; readable code.
    (make-regexps "\\b"
		  (list dtd-xml-keyword-list-2
			font-lock-type-face)
		  "\\b")
    (make-regexps "\\b"
		  (list dtd-xml-keyword-list-3
			font-lock-type-face)
		  "\\b")
    )
   dtd-common-font-lock-keywords-2
   )
  "Font lock keywords for use in XML DTDs.")

;; SGML DTDs
(defvar dtd-sgml-font-lock-keywords
  (append
   dtd-comment-declaration-keywords
   dtd-comment-in-declaration-keywords
   dtd-common-font-lock-keywords-1
   dtd-sgml-dtd-keywords
   (list
    ;;
    ;; Keywords
    (make-regexps
     (list dtd-sgml-keyword-list-1
	   font-lock-type-face)
     "\\b")
    ;;
    (make-regexps "\\b"
		  (list dtd-sgml-keyword-list-2
			font-lock-type-face)
		  "\\b")
    )
   dtd-common-font-lock-keywords-2
   )
  "Font lock keywords for SGML DTDs.")

;; SGML Declarations and SGML DTDs (since one can follow the other)
(defvar dtd-decl-font-lock-keywords
  (append
   dtd-comment-in-declaration-keywords
   dtd-common-font-lock-keywords-1
   (list
    ;;
    ;; SGML Declaration start and end
    ;;
    '("\\(<!SGML\\)\\s-+\\([^>]\\|>[^$]\\)+\\(>$\\)"
      (1 font-lock-keyword-face)
      (3 font-lock-keyword-face))
    ;;
    ;; Keywords
    (make-regexps "\\b"
		  (list
		   (append
		    dtd-common-sgml-declaration-keywords
		    dtd-charset-keywords
		    dtd-capacity-set-keywords
		    dtd-concrete-syntax-scope-keywords
		    dtd-concrete-syntax-keywords
		    dtd-features-keywords
		    dtd-appinfo-keywords
		    dtd-public-text-class-keywords)
		   font-lock-type-face)
		  "\\b")
    ;;
    ;; Minimum literal keywords
    ;;
    (make-regexps (list
		   dtd-sgml-declaration-minimum-literal-keywords
		   font-lock-type-face))
    ;;
    ;; Reserved names beginning with a non-word characters
    ;;
    (make-regexps
     (list dtd-xml-keyword-list-1
	   font-lock-type-face)
     "\\b")
    )
   dtd-common-font-lock-keywords-2
   )
  "Font lock keywords for SGML Declarations.")

;; SGML System Declarations
(defvar dtd-sys-decl-font-lock-keywords
  (append
   dtd-comment-in-declaration-keywords
   dtd-entity-reference-keywords
   (list
    ;;
    ;; System Declaration start and end
    ;;
    '("\\(<!SYSTEM\\)\\([^>]\\|>[^$]\\)+\\(>$\\)"
      (1 font-lock-keyword-face)
      (3 font-lock-keyword-face))
    ;;
    ;; Keywords
    ;;
    ;; Keywords starting with a non-word character
    ;;
    (make-regexps
     (list dtd-system-declaration-keyword-list-1
	   font-lock-type-face)
     "\\b")
    ;;
    ;; Other keywords
    ;;
    (make-regexps "\\b"
		  (list
		   (append
		    dtd-common-sgml-declaration-keywords
		    dtd-charset-keywords
		    dtd-capacity-set-keywords
		    dtd-concrete-syntax-scope-keywords
		    dtd-concrete-syntax-changes-keywords
		    dtd-concrete-syntax-keywords
		    dtd-features-keywords
		    dtd-validation-services-keywords
		    dtd-sdif-support-keywords
		    dtd-public-text-class-keywords)
		   font-lock-type-face)
		  "\\b")
    ;;
    ;; Minimum literal keywords
    ;;
    (make-regexps (list
		   dtd-sgml-declaration-minimum-literal-keywords
		   font-lock-type-face))
    ;;
    )
   dtd-common-font-lock-keywords-2
   )
  "Font lock keywords for System Declarations.")

(defun dtd-make-tdtd-font ()
  "Generate the file \"tdtd-font.el\"."
  (interactive)
  (find-file "tdtd-font.el")
  (kill-region (point-min) (point-max))
  (insert ";;;; tdtd-font.el --- Font-lock keywords for Tony's DTD mode\n")
  (insert ";; $\Id$\n")
  (insert ";; $\Name$\n")
  (insert ";;\n")
  (insert ";; Copyright (C) 1999, Tony Graham\n")
  (insert ";;\n")
  (insert ";; Author: Tony Graham <tgraham@mulberrytech.com>\n")
  (insert "\n")
  (insert ";;; This file is not part of GNU Emacs.\n")
  (insert "\n")
  (insert ";; This program is free software; you can redistribute it and/or\n")
  (insert ";; modify it under the terms of the GNU General Public License\n")
  (insert ";; as published by the Free Software Foundation; either version 2\n")
  (insert ";; of the License, or (at your option) any later version.\n")
  (insert ";;\n")
  (insert ";; This program is distributed in the hope that it will be useful,\n")
  (insert ";; but WITHOUT ANY WARRANTY; without even the implied warranty of\n")
  (insert ";; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n")
  (insert ";; GNU General Public License for more details.\n")
  (insert ";;\n")
  (insert ";; You should have received a copy of the GNU General Public License\n")
  (insert ";; along with this program; if not, write to the Free Software\n")
  (insert ";; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n")
  (insert "\n")
  (insert ";; Generated by tdtd-font-maker.el\n")
  (insert ";; Do not modify this file.  Make changes in tdtd-font-maker.el\n")
  (insert ";; and regenerate.\n")
  (insert "\n")
  (insert ";; Send bugs to tdtd-bug@menteith.com\n")
  (insert "\n\n")
  (insert (format "(defvar dtd-sgml-font-lock-keywords\n  '%s)\n\n"
		  (dtd-make-safe-var-def dtd-sgml-font-lock-keywords)))
  (insert (format "(defvar dtd-xml-font-lock-keywords\n  '%s)\n\n"
		  (dtd-make-safe-var-def dtd-xml-font-lock-keywords)))
  (insert (format "(defvar dtd-decl-font-lock-keywords\n  '%s)\n\n"
		  (dtd-make-safe-var-def dtd-decl-font-lock-keywords)))
  (insert (format "(defvar dtd-sys-decl-font-lock-keywords\n  '%s)\n\n"
		  (dtd-make-safe-var-def dtd-sys-decl-font-lock-keywords)))
  (insert "(provide 'tdtd-font)\n")
  ;; Don't bother saving a backup
  (setq backup-inhibited t)
  (save-buffer)
  (kill-buffer (current-buffer)))

(defun dtd-make-safe-var-def (var)
  "Tidy up a variable's definition so it's safe to output in a defun."
  (let ((var-string (format "%S" var)))
    (while (string-match "\t" var-string)
      (setq var-string (replace-match "\\t" nil t var-string)))
    (while (string-match "\n" var-string)
      (setq var-string (replace-match "\\n" nil t var-string)))
    (while (string-match "\r" var-string)
      (setq var-string (replace-match "\\r" nil t var-string)))
    (format "%s" var-string)))

(provide 'tdtd-font-maker)
tdtd/tdtd.el0100444000076500007650000017515006676775260013143 0ustar  camillecamille;;;; tdtd.el --- Tony's DTD mode
;; $Id: tdtd.el,v 1.41 1999/03/26 22:08:00 tkg Exp $
;; $Name: tdtd071 $

;; Copyright (C) 1996, 1997, 1998, 1999 Tony Graham

;; Author: Tony Graham <tgraham@mulberrytech.com>
;; Contributors: Juanma Barranquero, Adam di Carlo

;;; This file is not part of GNU Emacs.

;; 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
;; of the License, 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; if not, write to the Free Software
;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.


;;;; Commentary:

;; Macros for editing DTDs

;; Requires tdtd-font.el
;; Requires 'etags for `find-tag-default'
;; Requires 'imenu for "Goto" menu
;; Requires 'make-regexp for tdtd-font.el
;; Requires 'reporter for `dtd-submit-bug-report'
;; Send bugs to tdtd-bug@menteith.com


;;;; Code:
(eval-and-compile
  (require 'font-lock))
(eval-and-compile
  (autoload 'sgml-validate "psgml"))
(eval-and-compile
  (autoload 'reporter-submit-bug-report "reporter"))
;; XEmacs users don't always have imenu.el installed, so use
;; condition-case to cope if we cause an error by requiring imenu.
(eval-and-compile
  (condition-case nil
	(require 'imenu)
    (error nil)))

;; We need etags for `find-tag-default'
(require 'etags)
(require 'tdtd-font "tdtd-font")

(provide 'tdtd)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Version information

(defconst tdtd-version "0.7.1"
  "Version number of tdtd.")

(defun tdtd-version ()
  "Returns the value of the variable tdtd-version."
  tdtd-version)

(defconst tdtd-maintainer-address "tdtd-bug@menteith.com")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Variables

(defvar dtd-autodetect-type t
  "*Non-nil enables autodetection of XML or SGML when entering dtd-mode.")

(defvar dtd-xml-flag nil
  "*Non-nil enables XML-specific behaviour, where implemented.")

(defvar dtd-decl-flag nil
  "*Non-nil enables SGML Declaration-specific behaviour, where implemented.")

(defvar dtd-sys-decl-flag nil
  "*Non-nil enables System Declaration-specific behaviour, where implemented."
  )

(defun dtd-xml-p ()
  "Returns t when XML-specific behaviour is enabled, otherwise returns nil."
  (if dtd-xml-flag
      t nil))

(defun dtd-decl-p ()
  "Returns t when SGML Declaration-specific behaviour is enabled, otherwise nil."
  (if dtd-decl-flag
      t nil))

(defun dtd-sys-decl-p ()
  "Returns t when System Declaration-specific behaviour is enabled, otherwise nil."
  (if dtd-sys-decl-flag
      t nil))

(defvar dtd-indent-tabs-mode nil
  "*Initial value of indent-tabs-mode on entering dtd-mode")

(defvar dtd-default-filespec "*.dtd *.ent"
  "*Inital prompt value for `dtd-etags''s FILESPEC argument.")

(defvar dtd-filespec-history (list dtd-default-filespec)
  "Minibuffer history list for `dtd-etags' and `dtd-grep''s FILESPEC argument.")

(defvar dtd-grep-pattern-history nil
  "Minibuffer history list for `dtd-grep''s PATTERN argument.")

(defvar dtd-grep-case-sensitive-flag nil
  "*Non-nil disables case insensitive searches by `dtd-grep'.")

(defvar dtd-grep-command-format
  "grep -n %s -- '%s' %s"
  "*Format string for the grep command called by `dtd-grep'.")

;; Aren't shell escapes fun!
;; "\" -> "\\\\\\"
;; any other significant character -> "\\" + character
(defvar dtd-etags-regex-option
  "--regex=/\\<\\!\\\\\\(ELEMENT\\\\\\|ENTITY\\[\\ \\\\\\t]\\+%\\\\\\|NOTATION\\\\\\|ATTLIST\\\\\\)\\[\\ \\\\\\t]\\+\\\\\\(\\[^\\ \\\\\\t]\\+\\\\\\)/\\\\\\2/"
  "*Complete, including \"--regex=\", etags regular expression option string
for the etags command line for extracting tags (in the Emacs sense)
from DTDs.")
;; Use this regex with 4NT:
;; "--regex=\"/<!\\(ELEMENT\\|ENTITY[ \\t]+%%\\|NOTATION\\|ATTLIST\\)[\\t]+\\([^ \\t]+\\)/\\2/\""

(defvar dtd-etags-program "etags"
  "*Name (and possibly path) of the etags program")

(defvar dtd-etags-output-file "TAGS"
  "*Name of the etags output file")

(defvar dtd-attribute-type-history
  (list "CDATA" "ID" "IDREF" "IDREFS"
	"ENTITY" "ENTITIES" "NMTOKEN" "NMTOKENS" "NOTATION ")
  "Minibuffer history list for attribute types.")

(defvar dtd-attribute-tag-history nil
  "Minibuffer history list for attribute tags.")

(defvar dtd-attribute-default-history
  (list "#IMPLIED" "#REQUIRED")
  "Minibuffer history list for attribute types.")

(defvar dtd-default-element-type-name nil
  "Default for element type names.")

(defvar dtd-declared-element-type-names nil
  "List of element type names recently declared.")

(defvar dtd-referenced-element-type-names nil
  "List of element type names recently entered in content models.")

(defvar dtd-declared-parameter-entity-names nil
  "List of parameter entity names recently declared.")

(defvar dtd-referenced-parameter-entity-names nil
  "List of parameter entity names recently entered in content models.")

(defvar dtd-element-type-name-history nil
  "Minibuffer history list for element type names.")

(defvar dtd-parameter-entity-value-history nil
  "Minibuffer history list for parameter entity values.")

(defvar dtd-external-entity-public-history nil
  "Minibuffer history list for external entity public identifiers.")

(defvar dtd-external-entity-system-history nil
  "Minibuffer history list for external entity system identifiers.")

(defvar dtd-element-comment-history nil
  "Minibuffer history list for element comments.")

(defvar dtd-element-content-spec-history
  (list "(#PCDATA)" "EMPTY" "ANY")
  "Minibuffer history list for element content specifications.")

(defvar dtd-upcase-name-comment-flag nil
  "*Non-nil enables converting descriptive name comments to uppercase.")

(defvar dtd-prompt-descriptive-name t
  "*Non-nil enables prompting for descriptive names of elements, etc.")

(defvar dtd-prompt-descriptive-comment t
  "*Non-nil enables prompting for descriptive comments for elements, etc.")

(defvar dtd-outdent-attribute-pe nil
  "*Non-nil enables outdenting parameter entities used for attributes.")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Character sequences

(defvar dtd-sgml-mdo "<!"
  "*Markup Delimiter Open (MDO) character sequence")

(defvar dtd-sgml-mdc ">"
  "*Markup Delimiter Close (MDC) character sequence")

(defvar dtd-comment-start "<!--"
  "*Comment start character sequence")

(defvar dtd-comment-end "-->"
  "*Comment end character sequence")

;; SGML Syntactic Literals
(defvar dtd-empty-literal "EMPTY"
  "EMPTY element syntactic literal")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Variables controlling indentation

(defvar dtd-dtd-max-column 70
  "*Rightmost column for text in the DTD")

(defvar dtd-mdc-indent-column (1- dtd-dtd-max-column)
  "*Column at which to insert a MDC")

(defvar dtd-comment-start-column 25
  "*Column for starting text in a comment")

(defvar dtd-comment-max-column (- dtd-dtd-max-column 3)
  "*Maximum column number for text in a comment")

;; (defvar dtd-sgml-comment-max-column (- dtd-dtd-max-column 2))

(defvar dtd-element-name-column 12
  "*Column for element name in an element declaration")

(defvar dtd-element-tag-omission-column 25
  "*Column for inserting the omissibility indicators, if used")

(defvar dtd-element-content-spec-start-column 29
  "*Column at which to start content model")

(defvar dtd-element-content-spec-continuation-column 30
  "*Column at which to start second and subsequent lines of content model")

(defvar dtd-xml-element-content-spec-start-column 25
  "*Column at which to start XML content model")

(defvar dtd-xml-element-content-spec-continuation-column
  (1+ dtd-xml-element-content-spec-start-column)
  "*Column at which to start second and subsequent lines of XML content model")

(defvar dtd-entity-entity-value-start-column 24
  "*Column at which to start parameter entity's entity value")

(defvar dtd-entity-entity-value-continuation-column
  (1+ dtd-entity-entity-value-start-column)
  "*Column at which to start second and subsequent lines of parameter entity value")

(defvar dtd-attribute-name-column (+ dtd-element-name-column 2)
  "*Indent for inserting attribute names in attribute definitions")

(defvar dtd-attribute-default-column (- dtd-dtd-max-column 10)
  "*Indent for inserting attribute defaults in attribute definitions")

(defvar dtd-line-comment
  (concat
   dtd-comment-start
   " "
   (make-string
    (- dtd-dtd-max-column
       (length (concat dtd-comment-start "  " dtd-comment-end)))
    ?=)
   " "
   dtd-comment-end
   "\n")
  "*Separator comment line: \"<!-- ==== -->\".")

(defvar dtd-init-comment-column 16)

(defvar dtd-init-comment-fill-prefix
  (concat
   dtd-comment-start
   (make-string (- dtd-init-comment-column (length dtd-comment-start))
		?\ ))
  "*Prefix for comments making up the initial comment in a module.")

(defvar dtd-design-comment-start-column (+ (length dtd-comment-start) 2)
  "*Column for starting text in a \"Design Considerations\" comment")


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions

(defun dtd-autodetect-type ()
  "Check for initial declaration and set flags accordingly."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (skip-chars-forward "\\s-")
    (cond
     ((looking-at "<\\?xml")
      (setq dtd-xml-flag t)
      (setq dtd-decl-flag nil)
      (setq dtd-sys-decl-flag nil))
     ((looking-at "<!SGML")
      (setq dtd-xml-flag nil)
      (setq dtd-decl-flag t)
      (setq dtd-sys-decl-flag nil))
     ((looking-at "<!SYSTEM")
      (setq dtd-xml-flag nil)
      (setq dtd-decl-flag nil)
      (setq dtd-sys-decl-flag t))
     (t
      (setq dtd-xml-flag nil)
      (setq dtd-decl-flag nil)
      (setq dtd-sys-decl-flag nil)))))

;; If you want to untabify everything every time, add this to functions
;;  (untabify (point-min) (point-max))
;; Its easier to just not insert tabs using:
;;  (setq indent-tabs-mode nil)
(defun dtd-untabify-buffer ()
  "Untabify the entire buffer"
  (interactive)
  (untabify (point-min) (point-max)))

(defun dtd-fix-entities ()
  "Quick and dirty addition of \";\" to entity references lacking it"
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (while
	(re-search-forward "\\([%&][-A-Za-z0-9.:_]+\\)\\([^-A-Za-z0-9.:_;]\\)" nil t)
      (replace-match "\\1;\\2" nil nil)
      ;; match 2 may be the start of another entity reference
      (goto-char (match-beginning 2)))))

(defun dtd-indent-or-newline-to (target-column)
  "Indent to TARGET COLUMN or, if at or past target, insert newline and indent."
  (if (> (current-column)
	 target-column)
      (insert "\n"))
  (indent-to target-column))

(defun dtd-center-comment (comment)
  "Center a comment on line"
  (interactive "sComment: ")
  (insert dtd-comment-start)
  (indent-to (/ (- dtd-dtd-max-column (length comment)) 2))
  (insert comment)
  (indent-to dtd-comment-max-column)
  (insert dtd-comment-start)
  (insert "\n"))

(defun dtd-recenter-comment ()
  "Recenter text in a presumably modified comment line"
  (interactive)
  (save-excursion
    (save-match-data
      (beginning-of-line)
      (if (looking-at "^<!--\\s-*\\(\\w+\\(\\W+\\w+\\)*\\)\\s-*-->$")
	  (let ((contents (match-string 1)))
	    (delete-region (match-beginning 0) (match-end 0))
	    (dtd-center-comment contents))))))

(defun dtd-filled-comment (comment)
  "Insert a comment with \"=\" in most of the whitespace"
  (interactive "sComment: ")
  (dtd-comment comment "="))

;; TDTD house style puts all comments starting on a favourite column
(defun dtd-comment (comment &optional fill-character)
  "Insert COMMENT starting at the usual column.

With a prefix argument, e.g. \\[universal-argument] \\[dtd-comment], insert separator comment
lines above and below COMMENT in the manner of `dtd-big-comment'."
  (interactive "sComment: ")
  (if current-prefix-arg
      (insert dtd-line-comment))
  (insert "\n")
  (backward-char)
  (let ((fill-column (1- dtd-comment-max-column))
	(fill-prefix (make-string (1- dtd-comment-start-column) ?\ ))
	(comment-start dtd-init-comment-fill-prefix)
	(saved-auto-fill-function auto-fill-function))
    (auto-fill-mode 1)
    (insert dtd-comment-start)
    (if (and
	 (stringp fill-character)
	 (not (string-equal fill-character "")))
	(progn
	  (insert " ")
	  (insert (make-string (- dtd-comment-start-column
				  (current-column)
				  2)
			       (string-to-char fill-character)))))
    (indent-to (1- dtd-comment-start-column))
    (fill-region (point) (save-excursion
			   (insert comment)
			   (point))
		 nil
		 1
		 1)
    ;; The fill does the right thing, but in Emacs 19.34 it always ends with
    ;; an extra newline, so we delete the newline.
    (if (bolp)
	(delete-backward-char 1))
    (if (not saved-auto-fill-function)
	(auto-fill-mode 0))
    (if (and
	 (stringp fill-character)
	 (not (string-equal fill-character "")))
	(progn
	  (insert " ")
	  (insert (make-string (- dtd-comment-max-column
				  (current-column)
				  1)
			       (string-to-char fill-character)))))
    (indent-to dtd-comment-max-column)
    (insert dtd-comment-end)
    (insert "\n")
    (if current-prefix-arg
	(insert dtd-line-comment))
    (if font-lock-mode
	(save-excursion
	  (font-lock-fontify-region
	   (dtd-font-lock-region-point-min)
	   (dtd-font-lock-region-point-max))))))

(defun dtd-recomment ()
  "Fix text position in a presumably modified comment line"
  (interactive)
  (save-excursion
    (save-match-data
      (beginning-of-line)
      (if (looking-at "^\\(<!--*\\)?\\s-*\\([^ \t\n>]+\\([- \t]+[^- \t\n>]+\\)*\\)\\s-*\\(-->\\)?\n")
	  (let ((contents (match-string 2)))
	    (delete-region (match-beginning 0) (match-end 0))
	    (dtd-comment contents))))))

(defun dtd-join-comments (mark point)
  "Join comments by removing the \"interior\" comment delimiters."
  (interactive "r")
  (save-excursion
    (save-match-data
      (goto-char (min mark point))
      ;; Insert a comment start if there isn't one at the beginning.
      (if (not (looking-at dtd-comment-start))
	  (progn
	    (if (looking-at (make-string (length dtd-comment-start) ?\ ))
		(delete-region (match-beginning 0) (match-end 0)))
	    (insert dtd-comment-start)))
      ;; Delete the "interior" comment delimiters
      (goto-char (min mark point))
      (while (re-search-forward
	      (concat "[ \t\n]*" dtd-comment-end "\n" dtd-comment-start)
	      (max mark point) t)
	(replace-match (concat "\n" (make-string
				     (length dtd-comment-start)
				     ?\ ))
		       nil nil))))
  ;; Insert a comment end if there isn't one at the end
  ;;      (goto-char (- (max mark point)
  ;;		    (length dtd-comment-end)))
  ;;      (if (not (looking-at dtd-comment-end))
  ;;	  
  (if font-lock-mode
      (save-excursion
	(font-lock-fontify-region
	 (dtd-font-lock-region-point-min)
	 (dtd-font-lock-region-point-max)))))

(defun dtd-declare-element (element-tag element-name element-comment content-spec)
  "Insert an element type declaration at the current point.

ELEMENT-TAG is the element type name as it appears in start- and
end-tags.  ELEMENT-NAME is a descriptive name for the element.  It is
output as a comment.  ELEMENT-COMMENT is a further comment about the
element.  This comment is not output if ELEMENT-COMMENT is an empty
string.  CONTENT-SPEC is the element type's content specification.

When dtd-xml-flag in nil, the omitted tag minimization parameter is
output as part of the element type declaration.  When CONTENT-SPEC is
\"EMPTY\", the minimization parameter is \"- o\", otherwise it is \"- -\"

When dtd-upcase-name-comment-flag is non-nil, the text of the
descriptive element name is converted to uppercase before output.

ELEMENT-NAME is not prompted for if dtd-prompt-descriptive-name is
nil, and ELEMENT-COMMENT is not prompted for if
dtd-prompt-descriptive-comment is nil.

An example inserted element type declaration is as follows:

<!--                    Element name                               -->
<!--                    Comment about the element: what it's for,
                        or something about its behaviour           -->
<!ELEMENT  element-tag  - - (insert, your, content, specification,
                             here)                                   >
"
  (interactive
   ;; Hackery and fakery
   (let ((element-tag nil))
     (list (progn
	     ;; set element-tag to what's read from the minibuffer
	     (setq element-tag
		   (dtd-read-from-minibuffer
		    "Element tag: "
		    (car dtd-referenced-element-type-names)
		    'dtd-referenced-element-type-names))
	     ;; complain if element-tag is an empty string and there's no
	     ;; default
	     (if (string-equal element-tag "")
		 (if default
		     (setq element-tag default)
		   (error "You must supply an element tag name"))
	       ;; return element-tag is we had one already
	       element-tag))
	   (if dtd-prompt-descriptive-name
	       (read-from-minibuffer (format "<%s> descriptive name: "
					     element-tag)
				     ;; use element-tag as the default for
				     ;; the descriptive name since we often
				     ;; base the descriptive name on it
				     element-tag nil nil nil)
	     "")
	   (if dtd-prompt-descriptive-comment
	       (read-from-minibuffer (format "<%s> comment: "
					     element-tag)
				     nil nil nil
				     'dtd-element-comment-history)
	     "")
	   (read-from-minibuffer (format "<%s> content spec: "
					 element-tag)
				 nil nil nil
				 'dtd-element-content-spec-history))))
  (if (not
       (string-equal element-name ""))
      (progn
	(if dtd-upcase-name-comment-flag
	    (setq element-name (upcase element-name)))
	(dtd-comment element-name)))
  (if (not
       (string-equal element-comment ""))
      (dtd-comment element-comment))
  (insert "\n")
  (backward-char)
  (insert "<!ELEMENT  ")
  (insert element-tag)
  (if dtd-autodetect-type
      (dtd-autodetect-type))
  (if (not dtd-xml-flag)
      (progn
	(dtd-indent-or-newline-to (1- dtd-element-tag-omission-column))
	(if (string-equal content-spec dtd-empty-literal)
	    (insert "- o")
	  (insert "- -"))))
  (dtd-indent-or-newline-to
   (if dtd-xml-flag
       (1- dtd-xml-element-content-spec-start-column)
       (1- dtd-element-content-spec-start-column)))
  (let ((fill-column dtd-mdc-indent-column)
	(fill-prefix (make-string
		      (if dtd-xml-flag
			  (1-
			   dtd-xml-element-content-spec-continuation-column)
			  (1- dtd-element-content-spec-continuation-column))
			?\ ))
	(saved-auto-fill-function auto-fill-function))
    (auto-fill-mode 1)
    (fill-region (point) (save-excursion
			   (insert content-spec)
			   (point))
		 nil
		 1
		 1)
    ;; The fill does the right thing, but in Emacs 19.34 it always ends with
    ;; an extra newline, so we delete the newline.
    (if (bolp)
	(delete-backward-char 1))
;;    (setq content-spec-end (point))
    (if (not saved-auto-fill-function)
	(auto-fill-mode 0))
    (dtd-indent-or-newline-to dtd-mdc-indent-column)
    (insert (concat dtd-sgml-mdc "\n"))
    (auto-fill-mode nil)
    (if font-lock-mode
	(save-excursion
	  (font-lock-fontify-region
	   (dtd-font-lock-region-point-min)
	   (dtd-font-lock-region-point-max))))
    ;; Add to the list of element type names that we've already seen
    (add-to-list 'dtd-declared-element-type-names element-tag)
    ;; Work out whether we can remove element-tag from the list of
    ;; element type names that we've seen referenced in content models
    ;; and parameter entity declarations
    ;;
    ;; Before we work anything out, we need to remove element-type-name
    ;; from the start of dtd-referenced-element-type-names (since that's
    ;; the minibuffer history list variable)
    (setq dtd-referenced-element-type-names
	  (cdr dtd-referenced-element-type-names))
    (if (member element-tag dtd-referenced-element-type-names)
	;; There has to be an easier way to do this.
	(setq dtd-referenced-element-type-names
	      (catch 'roll-referenced-element-type-names
		(let ((bypassed-element-type-names nil))
		  (while (car dtd-referenced-element-type-names)
		    (let ((element-type-name
			   (car dtd-referenced-element-type-names)))
		      (setq dtd-referenced-element-type-names
			    (cdr dtd-referenced-element-type-names))
		      (if (equal element-tag element-type-name)
			  (throw
			   'roll-referenced-element-type-names
			   (append dtd-referenced-element-type-names
				   bypassed-element-type-names))
			(setq bypassed-element-type-names
			      (reverse
			       (add-to-list 'bypassed-element-type-names
					    element-type-name))))))))))
    (dtd-analyse-content-spec content-spec)))

(defun dtd-analyse-content-spec (content-spec)
  "Eventually, decide if need declarations for anything referenced in CONTENT-SPEC.

CONTENT-SPEC is an element type's content specification as provided to
`dtd-declare-element' or `dtd-declare-parameter-entity'."
;;  (message "%s" content-spec)
  (if (not (or (string-equal content-spec "ANY")
	       (string-equal content-spec "EMPTY")))
      (let ((match-index nil)
	    (token-list nil))
	(save-match-data
	  (while (string-match "\\(%?[A-Za-z#]+;?\\)"
			       content-spec match-index)
	    (add-to-list 'token-list (substring content-spec
					       (match-beginning 1)
					       (match-end 1)))
	    (setq match-index (match-end 0))))
	(while token-list
	  (let* ((token (car token-list))
		 (pe-flag (string-equal "%" (substring token 0 1))))
	    (if (not (string-equal token "#PCDATA"))
		(progn
;;		  (message "%s" token)
		  (if pe-flag
		      (progn
			(setq token (substring token
					       1
					       (1- (length token))))
			(if (not (member token
					 dtd-declared-parameter-entity-names))
			    (add-to-list
			     'dtd-referenced-parameter-entity-names
			     token)))
		    (if (not (member token
				     dtd-declared-element-type-names))
			(add-to-list 'dtd-referenced-element-type-names
				     token))))))
	    (setq token-list (cdr token-list))))))

(defun dtd-read-from-minibuffer (prompt default history)
  "Read from minibuffer with default and command history."
(let ((value nil))
  (if (string-equal
       ""
       (setq value
	     (read-from-minibuffer (if default
				       (format
					"%s(default `%s') "
					prompt default)
				     (format "%s" prompt))
				   nil nil nil
				   history)))
	     default
	     value)))

(defun dtd-declare-attribute
  (attribute-tag attribute-comment attribute-type attribute-default)
  "Declare an attribute.

ATTRIBUTE-TAG is the attribute name.  ATTRIBUTE-NAME is a descriptive
name for the attribute.  It is output as a comment.  ATTRIBUTE-COMMENT
is a further comment about the attribute.  This comment is not output
if ATTRIBUTE-COMMENT is an empty string.  ATTRIBUTE-TYPE is the
attribute's type or enumeration declaration.  ATTRIBUTE-DEFAULT is the
attribute's default.

ATTRIBUTE-COMMENT is not prompted for if
dtd-prompt-descriptive-comment is nil.

If called interactively and not after \"<!ATTLIST\", also calls
`dtd-declare-attribute-list' before prompting for ATTRIBUTE-TAG.

`dtd-declare-attribute' takes care of inserting or moving the \">\"
that closes the attribute list declaration."
  (interactive
   (let ((attribute-tag nil))
     ;; Hackery and fakery
     ;; If we're not after "<!ATTLIST", call dtd-declare-attribute-list.
     ;; This is an abomination, but don't know a better way to do it.
     ;;
     ;; Do `save-excursion', etc. while we check.
     (if (not (save-excursion
		(save-match-data
		  (re-search-backward "^<!" nil t)
		  (looking-at "<!ATTLIST"))))
	 (dtd-declare-attribute-list
	  ;; This is largely a repeat of the (interactive) statement
	  ;; in dtd-declare-attribute-list
	  (dtd-read-from-minibuffer
	   "Element type: "
	   (save-excursion
	     (save-match-data
	       (re-search-backward "^<!ELEMENT[ \t]+\\([^ \t\n]+\\)" nil t)
	       (match-string 1)))
	   'dtd-declared-element-type-names)))
     (list (setq attribute-tag
		 (dtd-read-from-minibuffer "Attribute tag: "
					   nil
					   'dtd-attribute-tag-history))
	   (if dtd-prompt-descriptive-comment
	       (dtd-read-from-minibuffer (format "\"%s\" comment: "
						 attribute-tag)
					 nil nil)
	     "")
	   (dtd-read-from-minibuffer
	    (format "\"%s\" type or enumeration: " attribute-tag)
	    (car dtd-attribute-type-history)
	    'dtd-attribute-type-history)
	   (dtd-read-from-minibuffer
	    (format "\"%s\" default: " attribute-tag)
	    (car dtd-attribute-default-history)
	    'dtd-attribute-default-history))))
  (if (and (stringp attribute-comment)
	   (not (string-equal attribute-comment "")))
      (save-excursion
	(re-search-backward "^<!ATTLIST" nil t)
	(insert dtd-comment-start)
	(dtd-indent-or-newline-to (1- dtd-attribute-name-column))
	(if (and
	     dtd-outdent-attribute-pe
	     (string-equal (substring attribute-tag 0 1) "%"))
	    (delete-backward-char 1))
	(insert attribute-tag)
	(dtd-indent-or-newline-to (1- dtd-comment-start-column))
	(let ((fill-column dtd-mdc-indent-column)
	      (fill-prefix (make-string
			    (1- dtd-comment-start-column) ?\ ))
	      (saved-auto-fill-function auto-fill-function))
	  ;;    (auto-fill-mode 1)
	  ;;    (setq content-spec-start (point))
	  (fill-region (point) (save-excursion
				 (insert attribute-comment)
				 (insert "\n")
				 (point))
		       nil
		       1
		       1)
	  ;; The fill does the right thing, but in Emacs 19.34 it
	  ;; always ends with an extra newline, so we delete the newline.
	  (if (bolp)
	      (delete-backward-char 1))
	  (dtd-indent-or-newline-to dtd-comment-max-column)
	  (insert dtd-comment-end)
	  (insert "\n"))
	;; Now see if we need to merge with a previous comment
	(let ((previous-comment-beginning
	       (save-excursion
		 (re-search-backward "<!" nil t 2)
		 (if (looking-at dtd-comment-start)
		     (point)
		   nil))))
	  (if previous-comment-beginning
	      (dtd-join-comments previous-comment-beginning (point))))))
  ;; Do it all again for the actual declaration
  (let ((fill-column dtd-mdc-indent-column)
	(fill-prefix (make-string
		      (1- dtd-comment-start-column) ?\ ))
	(saved-auto-fill-function auto-fill-function))
    ;; If we're after a declaration, delete the preceding mdc and any
    ;; whitespace around it.
    (if (not (save-excursion
	       (re-search-backward "^<!\\|>" nil t)
	       (looking-at "<!ATTLIST")))
	(save-excursion
	  (delete-region (point)
			 (save-excursion
			   (re-search-backward "[^ \t\n\r>]" nil t)
			   (1+ (point))))))
    (dtd-indent-or-newline-to (1- dtd-attribute-name-column))
    (if (string-equal (substring attribute-tag 0 1) "%")
	(delete-backward-char 1))
    (insert attribute-tag)
    (dtd-indent-or-newline-to (1- dtd-comment-start-column))
    (fill-region (point) (save-excursion
			   (insert attribute-type)
			   (insert "\n")
			   (point))
		 nil
		 1
		 1)
    ;; The fill does the right thing, but in Emacs 19.34 it always ends with
    ;; an extra newline, so we delete the newline.
    (if (bolp)
	(delete-backward-char 1))
    ;; We want the default to line up on dtd-attribute-default-column
    ;; unless it's too long, in which case we want one space between
    ;; the end of the default and the mdc (>).
    (if (< (length attribute-default)
	   (- dtd-dtd-max-column dtd-attribute-default-column 1))
	(dtd-indent-or-newline-to (1- dtd-attribute-default-column))
      (dtd-indent-or-newline-to (- dtd-dtd-max-column
				   (length attribute-default)
				   2)))
    (insert attribute-default)
    ;; Insert an mdc only if there isn't one between here and the
    ;; next mdo.
    (if (or (looking-at "<")
	    (not (save-excursion
		   (re-search-forward "^<!\\|>" nil t)
		   (goto-char (match-beginning 0))
		   (looking-at ">"))))
	(progn
	  (dtd-indent-or-newline-to dtd-mdc-indent-column)
	  (insert dtd-sgml-mdc)))
    (insert "\n")
    (if font-lock-mode
	(save-excursion
	  (font-lock-fontify-region
	   (dtd-font-lock-region-point-min)
	   (dtd-font-lock-region-point-max))))))

(defun dtd-declare-attribute-list (element-type-name)
  "Declare an attribute list."
  (interactive
   (list (dtd-read-from-minibuffer
	  "Element type: "
	  (save-excursion
	    (save-match-data
	      (re-search-backward "^<!ELEMENT[ \t]+\\([^ \t\n]+\\)" nil t)
	      (match-string 1)))
	  'dtd-declared-element-type-names)))
  (insert (concat "<!ATTLIST  " element-type-name "\n")))

(defun dtd-declare-notation
  (notation-tag notation-name notation-comment public-identifier system-identifier)
  "Insert a notation declaration.

NOTATION-TAG is the notation name as it appears in notation
references.  NOTATION-NAME is a descriptive name for the notation.  It
is output as a comment.  NOTATION-COMMENT is a further comment about
the notation.  The comment is not output if NOTATION-COMMENT is an
empty string.  PUBLIC-IDENTIFIER is the notation\'s public identifier
\(without '\"' characters).  SYSTEM-IDENTIFIER is the notation's system
identifier (without '\"' characters).

NOTATION-NAME is not prompted for if dtd-prompt-descriptive-name is
nil, and NOTATION-COMMENT is not prompted for if
dtd-prompt-descriptive-comment is nil.

An example inserted notation type declaration is as follows:

<!--                    Notation name                                -->
<!--                    Comment about the notation: what it's for,
                        or something about its behaviour           -->
<!NOTATION notation-tag   PUBLIC
\"-//Complete//NOTATION Public Identifier//EN\"
                                                                   -->
%notation-tag;
"
  (interactive
   ;; Hackery and fakery
   (let ((notation-tag nil))
     (list (progn
	     ;; set notation-tag to what's read from the minibuffer
	     (setq notation-tag
		   (dtd-read-from-minibuffer
		    "Notation tag: "
		    (car dtd-referenced-notation-type-names)
		    'dtd-referenced-notation-type-names))
	     ;; complain if notation-tag is an empty string and there's no
	     ;; default
	     (if (string-equal notation-tag "")
		 (if default
		     (setq notation-tag default)
		   (error "You must supply an notation tag name"))
	       ;; return notation-tag is we had one already
	       notation-tag))
	   (if dtd-prompt-descriptive-name
	       (read-from-minibuffer (format "`%s' descriptive name: "
					     notation-tag)
				     ;; use notation-tag as the default for
				     ;; the descriptive name since we often
				     ;; base the descriptive name on it
				     notation-tag nil nil nil)
	     "")
	   (if dtd-prompt-descriptive-comment
	       (read-from-minibuffer (format "`%s' comment: "
					     notation-tag)
				     nil nil nil
				     'dtd-notation-comment-history)
	     "")
	   (read-from-minibuffer (format "`%s' content spec: "
					 notation-tag)
				 nil nil nil
				 'dtd-notation-content-spec-history))))
  (if (not
       (string-equal notation-name ""))
      (progn
	(if dtd-upcase-name-comment-flag
	    (setq notation-name (upcase notation-name)))
	(dtd-comment notation-name)))
  (if (not
       (string-equal notation-comment ""))
	(dtd-comment notation-comment))
;;  (insert "\n")
;;  (backward-char)
  (insert "<!NOTATION ")
  (insert notation-tag)
  (dtd-indent-or-newline-to (1- dtd-element-content-spec-start-column))
  (if (not
       (string-equal public-identifier ""))
      (progn
	(insert "PUBLIC\n")
	(insert (concat "\"" public-identifier "\"\n")))
    (insert "SYSTEM "))
  (if (not
       (string-equal system-identifier ""))
      (insert (concat "\"" system-identifier "\"\n")))
  (indent-to dtd-mdc-indent-column)
  (insert dtd-sgml-mdc)
  (insert "\n")
  (if font-lock-mode
	(save-excursion
	  (font-lock-fontify-region
	   (dtd-font-lock-region-point-min)
	   (dtd-font-lock-region-point-max)))))

(defun dtd-declare-external-entity
  (entity-tag entity-name entity-comment public-identifier system-identifier)
  "Insert an entity declaration and references for an external public entity.

ENTITY-NAME is a descriptive name for the entity.  It is output as a
comment.  ENTITY-COMMENT is a further comment about the entity.  The
comment is not output if ENTITY-COMMENT is an empty string.
ENTITY-TAG is the entity name as it appears in entity references.
PUBLIC-IDENTIFIER is the entity's public identifier (without '\"'
characters).  SYSTEM-IDENTIFIER is the entity's system identifier
\(without '\"' characters).

ENTITY-NAME is not prompted for if dtd-prompt-descriptive-name is nil,
and ENTITY-COMMENT is not prompted for if
dtd-prompt-descriptive-comment is nil.

An example inserted entity type declaration is as follows:

<!--                    Entity name                                -->
<!--                    Comment about the entity: what it's for,
                        or something about its behaviour           -->
<!ENTITY % entity-tag   PUBLIC
\"-//Complete//ENTITY Public Identifier//EN\"
                                                                   -->
%entity-tag;
"
;;  (interactive "sEntity tag: \nsEntity name: \nsEntity comment: \nsPublic Identifier: \nsSystem Identifier: ")
  (interactive
   ;; Hackery and fakery
   (let ((entity-tag nil))
     (list (setq entity-tag
		 (read-from-minibuffer "External entity tag: "
				       nil nil nil
				       'dtd-referenced-parameter-entity-names))
	   (if dtd-prompt-descriptive-name
	       (read-from-minibuffer (format "`%%%s;\' descriptive name: "
					     entity-tag)
				     nil nil nil nil)
	     "")
	   (if dtd-prompt-descriptive-comment
	       (read-from-minibuffer (format "`%%%s;' comment: "
					     entity-tag)
				     nil nil nil nil)
	     "")
	   (read-from-minibuffer (format "`%%%s;' public identifier: "
					 entity-tag)
				 nil nil nil
				 'dtd-external-entity-public-history)
	   (read-from-minibuffer (format "`%%%s;' system identifier: "
					 entity-tag)
				 nil nil nil
				 'dtd-external-entity-system-history))))
  (if (not
       (string-equal entity-name ""))
      (progn
	(if dtd-upcase-name-comment-flag
	    (setq entity-name (upcase entity-name)))
	(dtd-comment entity-name)))
;;  (insert "\n")
  (if (not
       (string-equal entity-comment ""))
      (progn
	(dtd-comment entity-comment)
	(insert "\n")))
;;  (insert "\n")
;;  (backward-char)
  (insert "<!ENTITY % ")
  (insert entity-tag)
  (if dtd-autodetect-type
      (dtd-autodetect-type))
  (dtd-indent-or-newline-to
   (if dtd-xml-flag
       (1- dtd-xml-element-content-spec-start-column)
       (1- dtd-element-content-spec-start-column)))
  (if (not
       (string-equal public-identifier ""))
      (progn
	(insert "PUBLIC\n")
	(insert (concat "\"" public-identifier "\"\n")))
    (insert "SYSTEM "))
  (if (not
       (string-equal system-identifier ""))
      (insert (concat "\"" system-identifier "\"\n")))
  (indent-to dtd-mdc-indent-column)
  (insert (concat dtd-sgml-mdc "\n"))
  (insert (concat "%" entity-tag ";\n"))
  (if font-lock-mode
	(save-excursion
	  (font-lock-fontify-region
	   (dtd-font-lock-region-point-min)
	   (dtd-font-lock-region-point-max)))))

(defun dtd-declare-parameter-entity
  (entity-tag entity-name entity-comment entity-value)
  "Insert a parameter entity declaration at the current point.

ENTITY-NAME is a descriptive name for the entity.  It is output as a
comment.  ENTITY-COMMENT is a further comment about the entity.  The
comment is not output if ENTITY-COMMENT is an empty string.
ENTITY-TAG is the entity type name as it appears in start- and
end-tags.  ENTITY-VALUE is the entity's value specification, without
the '\"' characters.

ENTITY-NAME is not prompted for if dtd-prompt-descriptive-name is nil,
and ENTITY-COMMENT is not prompted for if
dtd-prompt-descriptive-comment is nil.

An example inserted parameter entity declaration is as follows:

<!--                    Entity name                               -->
<!--                    Comment about the entity: what it's for,
                        or something about its behaviour           -->
<!ENTITY % entity-tag   \"parameter, entity, contents\"                >
"
  (interactive
   ;; Hackery and fakery
   (let ((entity-tag nil))
     (list (setq entity-tag
		 (read-from-minibuffer "Entity tag: "
				       nil nil nil
				       'dtd-referenced-parameter-entity-names))
	   (if dtd-prompt-descriptive-name
	       (read-from-minibuffer (format "`%%%s;\' descriptive name: "
					     entity-tag)
				     nil nil nil nil)
	     "")
	   (if dtd-prompt-descriptive-comment
	       (read-from-minibuffer (format "`%%%s;' comment: "
					     entity-tag)
				     nil nil nil nil)
	     "")
	   (read-from-minibuffer (format "`%%%s;' value: "
					 entity-tag)
				 nil nil nil
				 'dtd-parameter-entity-value-history))))
  (if (not
       (string-equal entity-name ""))
      (progn
	(if dtd-upcase-name-comment-flag
	    (setq entity-name (upcase entity-name)))
	(dtd-comment entity-name)))
  (if (not
       (string-equal entity-comment ""))
      (dtd-comment entity-comment))
  (insert "<!ENTITY % ")
  (insert entity-tag)
  (dtd-indent-or-newline-to (1- dtd-entity-entity-value-start-column))
  (insert "\"")
  (let ((fill-column dtd-mdc-indent-column)
	(fill-prefix (make-string
		      (1- dtd-entity-entity-value-continuation-column) ?\ ))
	(saved-auto-fill-function auto-fill-function))
    (auto-fill-mode 1)
    (fill-region (point) (save-excursion
			   (insert entity-value)
			   (insert "\"")
			   (point))
		 nil
		 1
		 1)
    ;; The fill does the right thing, but in Emacs 19.34 it always ends with
    ;; an extra newline, so we delete the newline.
    (if (bolp)
	(delete-backward-char 1))
    (if (not saved-auto-fill-function)
	(auto-fill-mode 0))
    (dtd-indent-or-newline-to dtd-mdc-indent-column)
    (insert (concat dtd-sgml-mdc "\n"))
    (auto-fill-mode nil)
    (if font-lock-mode
	(save-excursion
	  (font-lock-fontify-region
	   (dtd-font-lock-region-point-min)
	   (dtd-font-lock-region-point-max))))
    (add-to-list 'dtd-declared-parameter-entity-names entity-tag)
    (if (member entity-tag dtd-referenced-parameter-entity-names)
	(setq dtd-referenced-parameter-entity-names
	      (delete entity-tag dtd-referenced-parameter-entity-names)))
    (dtd-analyse-content-spec entity-value)))

(defun dtd-insert-mdc ()
  "Without moving point, indent to usual column and insert MDC (>).
MDC = Markup Declaration Close"
  (interactive)
  (save-excursion
    (let ((current-point (point))
	  (mdc-column 0)
	  (mdc dtd-sgml-mdc))
      (if (if (looking-at dtd-sgml-mdo)
	      1
	    (re-search-backward (concat "^" dtd-sgml-mdo) nil t))
	  (progn
	    (if (looking-at dtd-comment-start)
	      (progn
		(setq mdc dtd-comment-end)
		(setq mdc-column dtd-comment-max-column))
	      (progn
		(setq mdc dtd-sgml-mdc)
		(setq mdc-column dtd-mdc-indent-column)))
	    (goto-char current-point)
	    (beginning-of-line)
	    (cond
	     ;; The main "looking-at" regular expression doesn't handle
	     ;; line containing just "-->" or ">" very well, so handle
	     ;; as special case.
	     ((looking-at "[ \t]*\\(--\\)?>$")
	      (progn
		;; Delete to the end of line so we can then insert our mdc
	       (delete-region (point) (save-excursion
					(end-of-line)
					(point)))
	       (indent-to mdc-column)
	       (insert mdc)))
	     ;; This is the main "looking-at" regular expression that
	     ;; handles most things
	     ((looking-at "^\\(\\(<!\\|[ \t]*\\)?\\(--\\)?[ \t]*\\([^ \t\n>]+\\([- \t]+[^- \t\n>]+\\)*\\)?\\)[ \t]*\\(\\(--\\)?>?\\)?$")
	      (progn
		;;(message ":%s:%s:%s:%s:" mdc mdc-column (match-string 4) (match-string 1))
		(goto-char (match-end 1))
		(delete-region (point) (save-excursion
					 (end-of-line)
					 (point)))
		(dtd-indent-or-newline-to mdc-column)
		(insert mdc))))))))
  (if font-lock-mode
      (save-excursion
	(font-lock-fontify-region
	 (dtd-font-lock-region-point-min)
	 (dtd-font-lock-region-point-max)))))

;; A work in progress
(defun dtd-fill-paragraph (&optional justify)
  "DTD fill paragraph function.  A work in progress."
  (interactive "P")
  ;;(insert "DTD")
  (save-excursion
    (if dtd-autodetect-type
	(dtd-autodetect-type))
    (let ((current-point (point))
	  (fill-column dtd-mdc-indent-column)
	  (fill-prefix (make-string
			(if dtd-xml-flag
			    (1-
			     dtd-xml-element-content-spec-continuation-column)
			  (1- dtd-element-content-spec-continuation-column))
			?\ ))
	  (saved-auto-fill-function auto-fill-function))
      (if (not (looking-at dtd-sgml-mdo))
	  (re-search-backward (concat "^" dtd-sgml-mdo) nil t))
      (if (looking-at "\\(<!ELEMENT\\)\\(\\s-+\\)")
	  (progn
	    (goto-char (match-end 1))
	    (delete-region (match-beginning 2) (match-end 2))
	    (dtd-indent-or-newline-to (1- dtd-element-name-column))
	    (if (looking-at "\\(\\sw\\|\\s_\\)+\\(\\s-+\\)")
		(progn
		  (message "It's an element")
		  (delete-region (match-beginning 2) (match-end 2))
		  (goto-char (match-end 1))
		  (if (looking-at "\\([-o]\\)\\s-+\\([-o]\\)\\s-+")
		      (let ((omit-start (match-string 1))
			    (omit-end (match-string 2)))
			(message "It has ommissibility indicators")
			(message "%s %s" omit-start omit-end)
			(delete-region
			 (match-beginning 0) (match-end 0))
			(dtd-indent-or-newline-to
			 (1- dtd-element-tag-omission-column))
			(insert omit-start)
			(insert " ")
			(insert omit-end)))
		  (dtd-indent-or-newline-to
		   (1-
		    (if dtd-xml-flag
			dtd-xml-element-content-spec-start-column
		      dtd-element-content-spec-start-column)))
		  (auto-fill-mode 1)
;;		  (let ((content-model-start (point))
;;			(content-model-end (save-excursion
;;					     (forward-sexp)
;;					     (point))))
		  (save-excursion
		    (let ((content-model-end (save-excursion
					       (forward-sexp)
					       (point))))
		    (while (re-search-forward
			    "\n+"
			    content-model-end t)
		      (replace-match " " nil nil))))
		  (fill-region (point) (save-excursion
					 (forward-sexp)
					 (point))
			       nil
			       1
			       1)
		  ;; The fill does the right thing, but it always ends with
		  ;; an extra newline, so we delete the newline.
		  (backward-char 1)
		  ;;    (setq content-spec-end (point))
		  (if (not saved-auto-fill-function)
		      (auto-fill-mode 0))))
	    (dtd-insert-mdc)
;;		  (insert "$")
;;	    (if (looking-at "\\(\\s-*\\)>")
;;		(progn
;;		  (delete-region (match-beginning 1) (match-end 1))
;;		  (dtd-indent-or-newline-to dtd-mdc-indent-column)
;;		  (insert "$")
))
;;		  (dtd-insert-mdc)
;;		  (insert "\n")
;;		  (auto-fill-mode nil)
		  (if font-lock-mode
	(save-excursion
	  (font-lock-fontify-region
	   (dtd-font-lock-region-point-min)
	   (dtd-font-lock-region-point-max)))))))
;;	    (if (looking-at "ANY\\|CDATA\\|EMPTY\\|RCDATA")
;;		(progn
;;		  (dtd-indent-or-newline-to
;;		   (1- dtd-element-content-spec-start-column)))
;;	      (message "It's something else"))))))
	;; If we're not doing anything, return nil so the built-in func