]> git.donarmstrong.com Git - lib.git/commitdiff
Initial user home directory commit
authorDon Armstrong <don@donarmstrong.com>
Sat, 1 Oct 2005 10:39:48 +0000 (10:39 +0000)
committerDon Armstrong <don@donarmstrong.com>
Sat, 1 Oct 2005 10:39:48 +0000 (10:39 +0000)
emacs_el/bibtex.el [new file with mode: 0644]
emacs_el/cperl-mode.el [new file with mode: 0644]
emacs_el/crontab-mode.el [new file with mode: 0644]
emacs_el/dna-mode.el [new file with mode: 0644]
emacs_el/ecasound.el [new file with mode: 0644]
emacs_el/emacs-wiki.el [new file with mode: 0644]
emacs_el/mode-compile.el [new file with mode: 0644]
emacs_el/mutt.el [new file with mode: 0644]
emacs_el/post.el [new file with mode: 0644]
emacs_el/psvn.el [new file with mode: 0644]

diff --git a/emacs_el/bibtex.el b/emacs_el/bibtex.el
new file mode 100644 (file)
index 0000000..fd50e01
--- /dev/null
@@ -0,0 +1,4073 @@
+;;; bibtex.el --- BibTeX mode for GNU Emacs
+
+;; Copyright (C) 1992, 1994, 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+
+;; Author: Stefan Schoef <schoef@offis.uni-oldenburg.de>
+;;     Bengt Martensson <bengt@mathematik.uni-Bremen.de>
+;;     Mark Shapiro <shapiro@corto.inria.fr>
+;;     Mike Newton <newton@gumby.cs.caltech.edu>
+;;     Aaron Larson <alarson@src.honeywell.com>
+;; Maintainer: none
+;; Keywords: BibTeX, LaTeX, TeX
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;  Major mode for editing and validating BibTeX files.
+
+;;  Usage:
+;;  See documentation for function bibtex-mode (or type "\M-x describe-mode"
+;;  when you are in BibTeX mode).
+
+;;  Todo:
+;;  Distribute texinfo file.
+
+;;; Code:
+
+(eval-when-compile
+  (require 'compile))
+
+\f
+;; Bug Reporting
+
+(defconst
+  bibtex-maintainer-address "Dirk Herrmann <D.Herrmann@tu-bs.de>")
+;; current maintainer
+
+(defconst
+  bibtex-maintainer-salutation "Hallo Dirk,")
+;; current maintainer
+
+(defconst
+  bibtex-version "(emacs 20.4)")
+;; current version of the bibtex.el file
+
+\f
+;; User Options:
+
+(defgroup bibtex nil
+  "BibTeX mode."
+  :group 'tex
+  :prefix "bibtex-")
+
+(defgroup bibtex-autokey nil
+  "Generates automatically a key from the author/editor and the title field"
+  :group 'bibtex
+  :prefix "bibtex-autokey-")
+
+(defcustom bibtex-mode-hook nil
+  "List of functions to call on entry to BibTeX mode."
+  :group 'bibtex
+  :type 'hook)
+
+(defcustom bibtex-field-delimiters 'braces
+  "*Controls type of field delimiters used.
+Set this to `braces' or `double-quotes' according to your personal
+preferences.  This variable is buffer-local."
+  :group 'bibtex
+  :type '(choice (const braces)
+                (const double-quotes)))
+(make-variable-buffer-local 'bibtex-field-delimiters)
+
+(defcustom bibtex-entry-delimiters 'braces
+  "*Controls type of entry delimiters used.
+Set this to `braces' or `parentheses' according to your personal
+preferences.  This variable is buffer-local."
+  :group 'bibtex
+  :type '(choice (const braces)
+                (const parentheses)))
+(make-variable-buffer-local 'bibtex-entry-delimiters)
+
+(defcustom bibtex-include-OPTcrossref '("InProceedings" "InCollection")
+  "*All entries listed here will have an OPTcrossref field."
+  :group 'bibtex
+  :type '(repeat string))
+
+(defcustom bibtex-include-OPTkey t
+  "*If non-nil, all entries will have an OPTkey field.
+If this is a string, it will be used as the initial field text.
+If this is a function, it will be called to generate the initial field text."
+  :group 'bibtex
+  :type '(choice (const :tag "None" nil)
+                (string :tag "Initial text")
+                (function :tag "Initialize Function" :value fun)
+                (other :tag "Default" t)))
+
+(defcustom bibtex-user-optional-fields
+  '(("annote" "Personal annotation (ignored)"))
+  "*List of optional fields the user wants to have always present.
+Entries should be of the same form as the OPTIONAL and
+CROSSREF-OPTIONAL lists in `bibtex-entry-field-alist' (see documentation
+of this variable for details)."
+  :group 'bibtex
+  :type '(repeat
+         (group (string :tag "Field")
+                (string :tag "Comment")
+                (option (group :inline t
+                               :extra-offset -4
+                               (choice :tag "Init" :value ""
+                                       string
+                                       function))))))
+
+(defcustom bibtex-entry-format '(opts-or-alts numerical-fields)
+  "*Controls type of formatting performed by `bibtex-clean-entry'.
+It may be t, nil, or a list of symbols out of the following:
+opts-or-alts        Delete empty optional and alternative fields and
+                      remove OPT and ALT prefixes from used fields.
+numerical-fields    Delete delimiters around numeral fields.
+page-dashes         Change double dashes in page field to single dash
+                      (for scribe compatibility).
+inherit-booktitle   If entry contains a crossref field and booktitle
+                      field is empty, it is set to the contents of the
+                      title field of the crossreferenced entry.
+                      Caution: this will work only if buffer is
+                       correctly sorted.
+realign             Realign entries, so that field texts and perhaps equal
+                      signs (depending on the value of
+                      `bibtex-align-at-equal-sign') begin in the same column.
+last-comma          Add or delete comma on end of last field in entry,
+                      according to value of `bibtex-comma-after-last-field'.
+delimiters          Change delimiters according to variables
+                      `bibtex-field-delimiters' and `bibtex-entry-delimiters'.
+unify-case          Change case of entry and field names.
+
+The value t means do all of the above formatting actions.
+The value nil means do no formatting at all."
+  :group 'bibtex
+  :type '(choice (const :tag "None" nil)
+                (const :tag "All" t)
+                (set :menu-tag "Some"
+                     (const opts-or-alts)
+                     (const numerical-fields)
+                     (const page-dashes)
+                     (const inherit-booktitle)
+                     (const realign)
+                     (const last-comma)
+                     (const delimiters)
+                     (const unify-case))))
+
+(defcustom bibtex-clean-entry-hook nil
+  "*List of functions to call when entry has been cleaned.
+Functions are called with point inside the cleaned entry, and the buffer
+narrowed to just the entry."
+  :group 'bibtex
+  :type 'hook)
+
+(defcustom bibtex-sort-ignore-string-entries t
+  "*If non-nil, BibTeX @String entries are not sort-significant.
+That means they are ignored when determining ordering of the buffer
+(e.g., sorting, locating alphabetical position for new entries, etc.).
+This variable is buffer-local."
+  :group 'bibtex
+  :type 'boolean)
+(make-variable-buffer-local 'bibtex-sort-ignore-string-entries)
+
+(defcustom bibtex-maintain-sorted-entries nil
+  "*If non-nil, BibTeX mode maintains all BibTeX entries in sorted order.
+Setting this variable to nil will strip off some comfort (e.g., TAB
+completion for reference keys in minibuffer, automatic detection of
+duplicates) from BibTeX mode.  See also `bibtex-sort-ignore-string-entries'.
+This variable is buffer-local."
+  :group 'bibtex
+  :type 'boolean)
+(make-variable-buffer-local 'bibtex-maintain-sorted-entries)
+
+(defcustom bibtex-field-kill-ring-max 20
+  "*Max length of `bibtex-field-kill-ring' before discarding oldest elements."
+  :group 'bibtex
+  :type 'integer)
+
+(defcustom bibtex-entry-kill-ring-max 20
+  "*Max length of `bibtex-entry-kill-ring' before discarding oldest elements."
+  :group 'bibtex
+  :type 'integer)
+
+(defcustom bibtex-parse-keys-timeout 60
+  "*Specifies interval for parsing buffers.
+All BibTeX buffers in Emacs are parsed if Emacs has been idle
+`bibtex-parse-keys-timeout' seconds.  Only buffers which were modified
+after last parsing and which are maintained in sorted order are parsed."
+  :group 'bibtex
+  :type 'integer)
+
+(defvar bibtex-entry-field-alist
+  '(
+    ("Article" . (((("author" "Author1 [and Author2 ...] [and others]")
+                    ("title" "Title of the article (BibTeX converts it to lowercase)")
+                    ("journal" "Name of the journal (use string, remove braces)")
+                    ("year" "Year of publication"))
+                  (("volume" "Volume of the journal")
+                    ("number" "Number of the journal (only allowed if entry contains volume)")
+                    ("pages" "Pages in the journal")
+                    ("month" "Month of the publication as a string (remove braces)")
+                    ("note" "Remarks to be put at the end of the \\bibitem")
+                   ("abstract" "Abstract of the publication")))
+                 ((("author" "Author1 [and Author2 ...] [and others]")
+                    ("title" "Title of the article (BibTeX converts it to lowercase)"))
+                  (("pages" "Pages in the journal")
+                    ("journal" "Name of the journal (use string, remove braces)")
+                    ("year" "Year of publication")
+                    ("volume" "Volume of the journal")
+                    ("number" "Number of the journal")
+                   ("month" "Month of the publication as a string (remove braces)")
+                    ("note" "Remarks to be put at the end of the \\bibitem")
+                   ("abstract" "Abstract of the publication")))))
+    ("Book" . (((("author" "Author1 [and Author2 ...] [and others]" "" t)
+                 ("editor" "Editor1 [and Editor2 ...] [and others]" "" t)
+                 ("title" "Title of the book")
+                 ("publisher" "Publishing company")
+                 ("year" "Year of publication"))
+               (("volume" "Volume of the book in the series")
+                 ("number" "Number of the book in a small series (overwritten by volume)")
+                 ("series" "Series in which the book appeared")
+                 ("address" "Address of the publisher")
+                ("edition" "Edition of the book as a capitalized English word")
+                 ("month" "Month of the publication as a string (remove braces)")
+                 ("note" "Remarks to be put at the end of the \\bibitem")))
+               ((("author" "Author1 [and Author2 ...] [and others]" "" t)
+                 ("editor" "Editor1 [and Editor2 ...] [and others]" "" t)
+                 ("title" "Title of the book"))
+                (("publisher" "Publishing company")
+                 ("year" "Year of publication")
+                 ("volume" "Volume of the book in the series")
+                 ("number" "Number of the book in a small series (overwritten by volume)")
+                 ("series" "Series in which the book appeared")
+                 ("address" "Address of the publisher")
+                ("edition" "Edition of the book as a capitalized English word")
+                 ("month" "Month of the publication as a string (remove braces)")
+                 ("note" "Remarks to be put at the end of the \\bibitem")))))
+    ("Booklet" . (((("title" "Title of the booklet (BibTeX converts it to lowercase)"))
+                  (("author" "Author1 [and Author2 ...] [and others]")
+                    ("howpublished" "The way in which the booklet was published")
+                    ("address" "Address of the publisher")
+                    ("month" "Month of the publication as a string (remove braces)")
+                    ("year" "Year of publication")
+                    ("note" "Remarks to be put at the end of the \\bibitem")))))
+    ("InBook" . (((("author" "Author1 [and Author2 ...] [and others]" "" t)
+                   ("editor" "Editor1 [and Editor2 ...] [and others]" "" t)
+                   ("title" "Title of the book")
+                   ("chapter" "Chapter in the book")
+                   ("publisher" "Publishing company")
+                   ("year" "Year of publication"))
+                 (("volume" "Volume of the book in the series")
+                   ("number" "Number of the book in a small series (overwritten by volume)")
+                   ("series" "Series in which the book appeared")
+                   ("type" "Word to use instead of \"chapter\"")
+                   ("address" "Address of the publisher")
+                  ("edition" "Edition of the book as a capitalized English word")
+                   ("month" "Month of the publication as a string (remove braces)")
+                   ("pages" "Pages in the book")
+                   ("note" "Remarks to be put at the end of the \\bibitem")))
+                ((("author" "Author1 [and Author2 ...] [and others]" "" t)
+                   ("editor" "Editor1 [and Editor2 ...] [and others]" "" t)
+                   ("title" "Title of the book")
+                   ("chapter" "Chapter in the book"))
+                 (("pages" "Pages in the book")
+                   ("publisher" "Publishing company")
+                   ("year" "Year of publication")
+                   ("volume" "Volume of the book in the series")
+                   ("number" "Number of the book in a small series (overwritten by volume)")
+                  ("series" "Series in which the book appeared")
+                   ("type" "Word to use instead of \"chapter\"")
+                   ("address" "Address of the publisher")
+                   ("edition" "Edition of the book as a capitalized English word")
+                   ("month" "Month of the publication as a string (remove braces)")
+                   ("note" "Remarks to be put at the end of the \\bibitem")))))
+    ("InCollection" . (((("author" "Author1 [and Author2 ...] [and others]")
+                         ("title" "Title of the article in book (BibTeX converts it to lowercase)")
+                        ("booktitle" "Name of the book")
+                         ("publisher" "Publishing company")
+                         ("year" "Year of publication"))
+                       (("editor" "Editor1 [and Editor2 ...] [and others]")
+                         ("volume" "Volume of the book in the series")
+                         ("number" "Number of the book in a small series (overwritten by volume)")
+                         ("series" "Series in which the book appeared")
+                         ("type" "Word to use instead of \"chapter\"")
+                         ("chapter" "Chapter in the book")
+                        ("pages" "Pages in the book")
+                         ("address" "Address of the publisher")
+                         ("edition" "Edition of the book as a capitalized English word")
+                         ("month" "Month of the publication as a string (remove braces)")
+                         ("note" "Remarks to be put at the end of the \\bibitem")))
+                      ((("author" "Author1 [and Author2 ...] [and others]")
+                         ("title" "Title of the article in book (BibTeX converts it to lowercase)")
+                         ("booktitle" "Name of the book"))
+                       (("pages" "Pages in the book")
+                         ("publisher" "Publishing company")
+                         ("year" "Year of publication")
+                        ("editor" "Editor1 [and Editor2 ...] [and others]")
+                         ("volume" "Volume of the book in the series")
+                         ("number" "Number of the book in a small series (overwritten by volume)")
+                         ("series" "Series in which the book appeared")
+                         ("type" "Word to use instead of \"chapter\"")
+                         ("chapter" "Chapter in the book")
+                         ("address" "Address of the publisher")
+                         ("edition" "Edition of the book as a capitalized English word")
+                         ("month" "Month of the publication as a string (remove braces)")
+                         ("note" "Remarks to be put at the end of the \\bibitem")))))
+    ("InProceedings" . (((("author" "Author1 [and Author2 ...] [and others]")
+                          ("title" "Title of the article in proceedings (BibTeX converts it to lowercase)")
+                          ("booktitle" "Name of the conference proceedings")
+                          ("year" "Year of publication"))
+                        (("editor" "Editor1 [and Editor2 ...] [and others]")
+                          ("volume" "Volume of the conference proceedings in the series")
+                          ("number" "Number of the conference proceedings in a small series (overwritten by volume)")
+                          ("series" "Series in which the conference proceedings appeared")
+                          ("pages" "Pages in the conference proceedings")
+                          ("address" "Location of the Proceedings")
+                          ("month" "Month of the publication as a string (remove braces)")
+                         ("organization" "Sponsoring organization of the conference")
+                          ("publisher" "Publishing company, its location")
+                          ("note" "Remarks to be put at the end of the \\bibitem")))
+                       ((("author" "Author1 [and Author2 ...] [and others]")
+                          ("title" "Title of the article in proceedings (BibTeX converts it to lowercase)"))
+                        (("booktitle" "Name of the conference proceedings")
+                         ("pages" "Pages in the conference proceedings")
+                          ("year" "Year of publication")
+                          ("editor" "Editor1 [and Editor2 ...] [and others]")
+                          ("volume" "Volume of the conference proceedings in the series")
+                          ("number" "Number of the conference proceedings in a small series (overwritten by volume)")
+                          ("series" "Series in which the conference proceedings appeared")
+                          ("address" "Location of the Proceedings")
+                          ("month" "Month of the publication as a string (remove braces)")
+                         ("organization" "Sponsoring organization of the conference")
+                          ("publisher" "Publishing company, its location")
+                          ("note" "Remarks to be put at the end of the \\bibitem")))))
+    ("Manual" . (((("title" "Title of the manual"))
+                 (("author" "Author1 [and Author2 ...] [and others]")
+                   ("organization" "Publishing organization of the manual")
+                   ("address" "Address of the organization")
+                   ("edition" "Edition of the manual as a capitalized English word")
+                  ("month" "Month of the publication as a string (remove braces)")
+                   ("year" "Year of publication")
+                   ("note" "Remarks to be put at the end of the \\bibitem")))))
+    ("MastersThesis" . (((("author" "Author1 [and Author2 ...] [and others]")
+                          ("title" "Title of the master\'s thesis (BibTeX converts it to lowercase)")
+                          ("school" "School where the master\'s thesis was written")
+                          ("year" "Year of publication"))
+                         (("type" "Type of the master\'s thesis (if other than \"Master\'s thesis\")")
+                         ("address" "Address of the school (if not part of field \"school\") or country")
+                          ("month" "Month of the publication as a string (remove braces)")
+                          ("note" "Remarks to be put at the end of the \\bibitem")))))
+    ("Misc" . ((()
+               (("author" "Author1 [and Author2 ...] [and others]")
+                 ("title" "Title of the work (BibTeX converts it to lowercase)")
+                 ("howpublished" "The way in which the work was published")
+                 ("month" "Month of the publication as a string (remove braces)")
+                 ("year" "Year of publication")
+                 ("note" "Remarks to be put at the end of the \\bibitem")))))
+    ("PhdThesis" . (((("author" "Author1 [and Author2 ...] [and others]")
+                      ("title" "Title of the PhD. thesis")
+                      ("school" "School where the PhD. thesis was written")
+                      ("year" "Year of publication"))
+                     (("type" "Type of the PhD. thesis")
+                      ("address" "Address of the school (if not part of field \"school\") or country")
+                      ("month" "Month of the publication as a string (remove braces)")
+                      ("note" "Remarks to be put at the end of the \\bibitem")))))
+    ("Proceedings" . (((("title" "Title of the conference proceedings")
+                        ("year" "Year of publication"))
+                      (("booktitle" "Title of the proceedings for cross references")
+                       ("editor" "Editor1 [and Editor2 ...] [and others]")
+                        ("volume" "Volume of the conference proceedings in the series")
+                        ("number" "Number of the conference proceedings in a small series (overwritten by volume)")
+                        ("series" "Series in which the conference proceedings appeared")
+                        ("address" "Location of the Proceedings")
+                        ("month" "Month of the publication as a string (remove braces)")
+                       ("organization" "Sponsoring organization of the conference")
+                        ("publisher" "Publishing company, its location")
+                        ("note" "Remarks to be put at the end of the \\bibitem")))))
+    ("TechReport" . (((("author" "Author1 [and Author2 ...] [and others]")
+                       ("title" "Title of the technical report (BibTeX converts it to lowercase)")
+                       ("institution" "Sponsoring institution of the report")
+                       ("year" "Year of publication"))
+                     (("type" "Type of the report (if other than \"technical report\")")
+                       ("number" "Number of the technical report")
+                       ("address" "Address of the institution (if not part of field \"institution\") or country")
+                       ("month" "Month of the publication as a string (remove braces)")
+                       ("note" "Remarks to be put at the end of the \\bibitem")))))
+    ("Unpublished" . (((("author" "Author1 [and Author2 ...] [and others]")
+                        ("title" "Title of the unpublished work (BibTeX converts it to lowercase)")
+                        ("note" "Remarks to be put at the end of the \\bibitem"))
+                      (("month" "Month of the publication as a string (remove braces)")
+                        ("year" "Year of publication")))))
+    )
+
+  "Defines entry types and their associated fields.
+List of
+(ENTRY-NAME (REQUIRED OPTIONAL) (CROSSREF-REQUIRED CROSSREF-OPTIONAL))
+triples.
+If the third element is nil, the first pair is always used.
+If not, the second pair is used in the case of presence of a crossref
+field and the third in the case of absence.
+REQUIRED, OPTIONAL, CROSSREF-REQUIRED and CROSSREF-OPTIONAL are lists.
+Each element of these lists is a list of the form
+(FIELD-NAME COMMENT-STRING INIT ALTERNATIVE-FLAG).
+COMMENT-STRING, INIT, and ALTERNATIVE-FLAG are optional.
+FIELD-NAME is the name of the field, COMMENT-STRING the comment to
+appear in the echo area, INIT is either the initial content of the
+field or a function, which is called to determine the initial content
+of the field, and ALTERNATIVE-FLAG (either nil or t) marks if the
+field is an alternative.  ALTERNATIVE-FLAG may be t only in the
+REQUIRED or CROSSREF-REQUIRED lists.")
+
+(defvar bibtex-comment-start "@Comment ")
+
+(defcustom bibtex-add-entry-hook nil
+  "List of functions to call when entry has been inserted."
+  :group 'bibtex
+  :type 'hook)
+
+(defcustom bibtex-predefined-month-strings
+  '(
+    ("jan") ("feb") ("mar") ("apr") ("may") ("jun")
+    ("jul") ("aug") ("sep") ("oct") ("nov") ("dec")
+    )
+  "Alist of month string definitions.
+Should contain all strings used for months in the BibTeX style files.
+Each element is a list with just one element: the string."
+  :group 'bibtex
+  :type '(repeat
+         (list string)))
+
+(defcustom bibtex-predefined-strings
+  (append
+   bibtex-predefined-month-strings
+   '(
+     ("acmcs") ("acta") ("cacm") ("ibmjrd") ("ibmsj") ("ieeese")
+     ("ieeetc") ("ieeetcad") ("ipl") ("jacm") ("jcss") ("scp")
+     ("sicomp") ("tcs") ("tocs") ("tods") ("tog") ("toms") ("toois")
+     ("toplas")
+     ))
+  "Alist of string definitions.
+Should contain the strings defined in the BibTeX style files.  Each
+element is a list with just one element: the string."
+  :group 'bibtex
+  :type '(repeat
+         (list string)))
+
+(defcustom bibtex-string-files nil
+  "*List of BibTeX files containing string definitions.
+Those files must be specified using pathnames relative to the
+directories specified in `bibtex-string-file-path'.  This variable is only
+evaluated when BibTeX mode is entered (i.e., when loading the BibTeX
+file)."
+  :group 'bibtex
+  :type '(repeat file))
+
+(defvar bibtex-string-file-path (getenv "BIBINPUTS")
+  "*Colon separated list of paths to search for `bibtex-string-files'.")
+
+(defcustom bibtex-help-message t
+  "*If not nil print help messages in the echo area on entering a new field."
+  :group 'bibtex
+  :type 'boolean)
+
+(defcustom bibtex-autokey-prefix-string ""
+  "*String to use as a prefix for all generated keys.
+See the documentation of function `bibtex-generate-autokey' for more detail."
+  :group 'bibtex-autokey
+  :type 'string)
+
+(defcustom bibtex-autokey-names 1
+  "*Number of names to use for the automatically generated reference key.
+If this is variable is nil, all names are used.
+Possibly more names are used according to `bibtex-autokey-names-stretch'.
+See the documentation of function `bibtex-generate-autokey' for more detail."
+  :group 'bibtex-autokey
+  :type '(choice (const :tag "All" infty)
+                integer))
+
+(defcustom bibtex-autokey-names-stretch 0
+  "*Number of names that can additionally be used.
+These names are used only, if all names are used then.
+See the documentation of function `bibtex-generate-autokey' for details."
+  :group 'bibtex-autokey
+  :type 'integer)
+
+(defcustom bibtex-autokey-additional-names ""
+  "*String to prepend to the generated key if not all names could be used.
+See the documentation of function `bibtex-generate-autokey' for details."
+  :group 'bibtex-autokey
+  :type 'string)
+
+(defvar bibtex-autokey-transcriptions
+  '(
+    ;; language specific characters
+    ("\\\\aa" "a")
+    ("\\\\AA" "A")
+    ("\\\"a\\|\\\\\\\"a\\|\\\\ae" "ae")
+    ("\\\"A\\|\\\\\\\"A\\|\\\\AE" "Ae")
+    ("\\\\i" "i")
+    ("\\\\j" "j")
+    ("\\\\l" "l")
+    ("\\\\L" "L")
+    ("\\\"o\\|\\\\\\\"o\\|\\\\o\\|\\\\oe" "oe")
+    ("\\\"O\\|\\\\\\\"O\\|\\\\O\\|\\\\OE" "Oe")
+    ("\\\"s\\|\\\\\\\"s" "ss")
+    ("\\\"u\\|\\\\\\\"u" "ue")
+    ("\\\"U\\|\\\\\\\"U" "Ue")
+    ;; accents
+    ("\\\\`\\|\\\\'\\|\\\\\\^\\|\\\\~\\|\\\\=\\|\\\\\\.\\|\\\\u\\|\\\\v\\|\\\\H\\|\\\\t\\|\\\\c\\|\\\\d\\|\\\\b" "")
+    ;; braces
+    ("{" "") ("}" ""))
+  "Alist of (old-regexp new-string) pairs.
+Used by the default values of `bibtex-autokey-name-change-strings' and
+`bibtex-autokey-titleword-change-strings'.  Defaults to translating some
+language specific characters to their ASCII transcriptions, and
+removing any character accents.")
+
+(defcustom bibtex-autokey-name-change-strings
+  bibtex-autokey-transcriptions
+  "Alist of (OLD-REGEXP NEW-STRING) pairs.
+Any part of name matching a OLD-REGEXP is replaced by NEW-STRING.
+Case is significant in OLD-REGEXP.  All regexps are tried in the
+order in which they appear in the list, so be sure to avoid inifinite
+loops here.
+See the documentation of function `bibtex-generate-autokey' for details."
+  :group 'bibtex-autokey
+  :type '(repeat
+         (list (regexp :tag "Old")
+               (string :tag "New"))))
+
+(defcustom bibtex-autokey-name-case-convert 'downcase
+  "*Function called for each name to perform case conversion.
+See the documentation of function `bibtex-generate-autokey' for more detail."
+  :group 'bibtex-autokey
+  :type '(choice (const :tag "Preserve case" identity)
+                (const :tag "Downcase" downcase)
+                (const :tag "Capitalize" capitalize)
+                (const :tag "Upcase" upcase)
+                (function :tag "Conversion function")))
+
+(defcustom bibtex-autokey-name-length 'infty
+  "*Number of characters from name to incorporate into key.
+If this is set to anything but a number, all characters are used.
+See the documentation of function `bibtex-generate-autokey' for details."
+  :group 'bibtex-autokey
+  :type '(choice (const :tag "All" infty)
+                integer))
+
+(defcustom bibtex-autokey-name-separator ""
+  "*String that comes between any two names in the key.
+See the documentation of function `bibtex-generate-autokey' for details."
+  :group 'bibtex-autokey
+  :type 'string)
+
+(defcustom bibtex-autokey-year-length 2
+  "*Number of rightmost digits from the year field to incorporate into key.
+See the documentation of function `bibtex-generate-autokey' for details."
+  :group 'bibtex-autokey
+  :type 'integer)
+
+(defcustom bibtex-autokey-year-use-crossref-entry t
+  "*If non-nil use year field from crossreferenced entry if necessary.
+If this variable is non-nil and the current entry has no year, but a
+valid crossref entry, the year field from the crossreferenced entry is
+used.
+See the documentation of function `bibtex-generate-autokey' for details."
+  :group 'bibtex-autokey
+  :type 'boolean)
+
+(defcustom bibtex-autokey-titlewords 5
+  "*Number of title words to use for the automatically generated reference key.
+If this is set to anything but a number, all title words are used.
+Possibly more words from the title are used according to
+`bibtex-autokey-titlewords-stretch'.
+See the documentation of function `bibtex-generate-autokey' for details."
+  :group 'bibtex-autokey
+  :type '(choice (const :tag "All" infty)
+                integer))
+
+(defcustom bibtex-autokey-title-terminators
+  '("\\." "!"  "\\?" ":" ";" "--")
+  "*Regexp list defining the termination of the main part of the title.
+Case of the regexps is ignored.
+See the documentation of function `bibtex-generate-autokey' for details."
+  :group 'bibtex-autokey
+  :type '(repeat regexp))
+
+(defcustom bibtex-autokey-titlewords-stretch 2
+  "*Number of words that can additionally be used from the title.
+These words are used only, if a sentence from the title can be ended then.
+See the documentation of function `bibtex-generate-autokey' for details."
+  :group 'bibtex-autokey
+  :type 'integer)
+
+(defcustom bibtex-autokey-titleword-ignore
+  '("A" "An" "On" "The" "Eine?" "Der" "Die" "Das"
+    "[^A-Z].*" ".*[^a-zA-Z0-9].*")
+  "*Determines words from the title that are not to be used in the key.
+Each item of the list is a regexp.  If a word of the title matchs a
+regexp from that list, it is not included in the title part of the key.
+See the documentation of function `bibtex-generate-autokey' for details."
+  :group 'bibtex-autokey
+  :type '(repeat regexp))
+
+(defcustom bibtex-autokey-titleword-case-convert 'downcase
+  "*Function called for each titleword to perform case conversion.
+See the documentation of function `bibtex-generate-autokey' for more detail."
+  :group 'bibtex-autokey
+  :type '(choice (const :tag "Preserve case" identity)
+                (const :tag "Downcase" downcase)
+                (const :tag "Capitalize" capitalize)
+                (const :tag "Upcase" upcase)
+                (function :tag "Conversion function")))
+
+(defcustom bibtex-autokey-titleword-abbrevs nil
+  "*Determines exceptions to the usual abbreviation mechanism.
+An alist of (OLD-REGEXP NEW-STRING) pairs.  Case is ignored
+in matching against OLD-REGEXP, and the first matching pair is used.
+See the documentation of function `bibtex-generate-autokey' for details.")
+
+(defcustom bibtex-autokey-titleword-change-strings
+  bibtex-autokey-transcriptions
+  "Alist of (OLD-REGEXP NEW-STRING) pairs.
+Any part of title word matching a OLD-REGEXP is replaced by NEW-STRING.
+Case is significant in OLD-REGEXP.  All regexps are tried in the
+order in which they appear in the list, so be sure to avoid inifinite
+loops here.
+See the documentation of function `bibtex-generate-autokey' for details."
+  :group 'bibtex-autokey
+  :type '(repeat
+         (list (regexp :tag "Old")
+               (string :tag "New"))))
+
+(defcustom bibtex-autokey-titleword-length 5
+  "*Number of characters from title words to incorporate into key.
+If this is set to anything but a number, all characters are used.
+See the documentation of function `bibtex-generate-autokey' for details."
+  :group 'bibtex-autokey
+  :type '(choice (const :tag "All" infty)
+                integer))
+
+(defcustom bibtex-autokey-titleword-separator "_"
+  "*String to be put between the title words.
+See the documentation of function `bibtex-generate-autokey' for details."
+  :group 'bibtex-autokey
+  :type 'string)
+
+(defcustom bibtex-autokey-name-year-separator ""
+  "*String to be put between name part and year part of key.
+See the documentation of function `bibtex-generate-autokey' for details."
+  :group 'bibtex-autokey
+  :type 'string)
+
+(defcustom bibtex-autokey-year-title-separator ":_"
+  "*String to be put between name part and year part of key.
+See the documentation of function `bibtex-generate-autokey' for details."
+  :group 'bibtex-autokey
+  :type 'string)
+
+(defcustom bibtex-autokey-edit-before-use t
+  "*If non-nil, user is allowed to edit the generated key before it is used."
+  :group 'bibtex-autokey
+  :type 'boolean)
+
+(defcustom bibtex-autokey-before-presentation-function nil
+  "Function to call before the generated key is presented.
+If non-nil this should be a single function, which is called before
+the generated key is presented (in entry or, if
+`bibtex-autokey-edit-before-use' is t, in minibuffer).  This function
+must take one argument (the automatically generated key), and must
+return with a string (the key to use)."
+  :group 'bibtex-autokey
+  :type '(choice (const nil) function))
+
+(defcustom bibtex-entry-offset 0
+  "*Offset for BibTeX entries.
+Added to the value of all other variables which determine colums."
+  :group 'bibtex
+  :type 'integer)
+
+(defcustom bibtex-field-indentation 2
+  "*Starting column for the name part in BibTeX fields."
+  :group 'bibtex
+  :type 'integer)
+
+(defcustom bibtex-text-indentation
+  (+
+   bibtex-field-indentation
+   (length "organization = "))
+  "*Starting column for the text part in BibTeX fields.
+Should be equal to the space needed for the longest name part."
+  :group 'bibtex
+  :type 'integer)
+
+(defcustom bibtex-contline-indentation
+  (+ bibtex-text-indentation 1)
+  "*Starting column for continuation lines of BibTeX fields."
+  :group 'bibtex
+  :type 'integer)
+
+(defcustom bibtex-align-at-equal-sign nil
+  "*If non-nil, align fields at equal sign instead of field text.
+If non-nil, the column for the equal sign is
+the value of `bibtex-text-indentation', minus 2."
+  :group 'bibtex
+  :type 'boolean)
+
+(defcustom bibtex-comma-after-last-field nil
+  "*If non-nil, a comma is put at end of last field in the entry template."
+  :group 'bibtex
+  :type 'boolean)
+
+;; bibtex-font-lock-keywords is a user option as well, but since the
+;; patterns used to define this variable are defined in a later
+;; section of this file, it is defined later.
+\f
+;; Special support taking care of variants
+(if (boundp 'mark-active)
+    (defun bibtex-mark-active ()
+      ;; In Emacs mark-active indicates if mark is active.
+      mark-active)
+  (defun bibtex-mark-active ()
+    ;; In XEmacs (mark) returns nil when not active.
+    (if zmacs-regions (mark) (mark t))))
+
+(if (fboundp 'run-with-idle-timer)
+    ;; timer.el is distributed with Emacs
+    (fset 'bibtex-run-with-idle-timer 'run-with-idle-timer)
+  ;; timer.el is not distributed with XEmacs
+  ;; Notice that this does not (yet) pass the arguments, but they
+  ;; are not used (yet) in bibtex.el. Fix if needed.
+  (defun bibtex-run-with-idle-timer (secs repeat function &rest args)
+    (start-itimer "bibtex" function secs (if repeat secs nil) t)))
+
+\f
+;; Support for hideshow minor mode
+(defun bibtex-hs-forward-sexp (arg)
+  "Replacement for `forward-sexp' to be used by `hs-minor-mode'."
+  (if (< arg 0)
+      (backward-sexp 1)
+    (if (looking-at "@\\S(*\\s(")
+       (progn
+         (goto-char (match-end 0))
+         (forward-char -1)
+         (forward-sexp 1))
+      (forward-sexp 1))))
+
+(add-to-list
+ 'hs-special-modes-alist
+ '(bibtex-mode "@\\S(*\\s(" "\\s)" nil bibtex-hs-forward-sexp nil))
+
+\f
+;; Syntax Table, Keybindings and BibTeX Entry List
+(defvar bibtex-mode-syntax-table
+  (let ((st (make-syntax-table)))
+    (modify-syntax-entry ?\" "\"" st)
+    (modify-syntax-entry ?$ "$$  " st)
+    (modify-syntax-entry ?% "<   " st)
+    (modify-syntax-entry ?' "w   " st)
+    (modify-syntax-entry ?@ "w   " st)
+    (modify-syntax-entry ?\\ "\\" st)
+    (modify-syntax-entry ?\f ">   " st)
+    (modify-syntax-entry ?\n ">   " st)
+    (modify-syntax-entry ?~ " " st)
+    st))
+
+(defvar bibtex-mode-map
+  (let ((km (make-sparse-keymap)))
+    ;; The Key `C-c&' is reserved for reftex.el
+    (define-key km "\t" 'bibtex-find-text)
+    (define-key km "\n" 'bibtex-next-field)
+    (define-key km "\M-\t" 'bibtex-complete-string)
+    (define-key km [(meta tab)] 'bibtex-complete-key)
+    (define-key km "\C-c\"" 'bibtex-remove-delimiters)
+    (define-key km "\C-c{" 'bibtex-remove-delimiters)
+    (define-key km "\C-c}" 'bibtex-remove-delimiters)
+    (define-key km "\C-c\C-c" 'bibtex-clean-entry)
+    (define-key km "\C-c\C-q" 'bibtex-fill-entry)
+    (define-key km "\C-c?" 'bibtex-print-help-message)
+    (define-key km "\C-c\C-p" 'bibtex-pop-previous)
+    (define-key km "\C-c\C-n" 'bibtex-pop-next)
+    (define-key km "\C-c\C-k" 'bibtex-kill-field)
+    (define-key km "\C-c\M-k" 'bibtex-copy-field-as-kill)
+    (define-key km "\C-c\C-w" 'bibtex-kill-entry)
+    (define-key km "\C-c\M-w" 'bibtex-copy-entry-as-kill)
+    (define-key km "\C-c\C-y" 'bibtex-yank)
+    (define-key km "\C-c\M-y" 'bibtex-yank-pop)
+    (define-key km "\C-c\C-d" 'bibtex-empty-field)
+    (define-key km "\C-c\C-f" 'bibtex-make-field)
+    (define-key km "\C-c$" 'bibtex-ispell-abstract)
+    (define-key km "\M-\C-a" 'bibtex-beginning-of-entry)
+    (define-key km "\M-\C-e" 'bibtex-end-of-entry)
+    (define-key km "\C-\M-l" 'bibtex-reposition-window)
+    (define-key km "\C-\M-h" 'bibtex-mark-entry)
+    (define-key km "\C-c\C-b" 'bibtex-entry)
+    (define-key km "\C-c\C-rn" 'bibtex-narrow-to-entry)
+    (define-key km "\C-c\C-rw" 'widen)
+    (define-key km "\C-c\C-o" 'bibtex-remove-OPT-or-ALT)
+    (define-key km "\C-c\C-e\C-i" 'bibtex-InProceedings)
+    (define-key km "\C-c\C-ei" 'bibtex-InCollection)
+    (define-key km "\C-c\C-eI" 'bibtex-InBook)
+    (define-key km "\C-c\C-e\C-a" 'bibtex-Article)
+    (define-key km "\C-c\C-e\C-b" 'bibtex-InBook)
+    (define-key km "\C-c\C-eb" 'bibtex-Book)
+    (define-key km "\C-c\C-eB" 'bibtex-Booklet)
+    (define-key km "\C-c\C-e\C-c" 'bibtex-InCollection)
+    (define-key km "\C-c\C-e\C-m" 'bibtex-Manual)
+    (define-key km "\C-c\C-em" 'bibtex-MastersThesis)
+    (define-key km "\C-c\C-eM" 'bibtex-Misc)
+    (define-key km "\C-c\C-e\C-p" 'bibtex-InProceedings)
+    (define-key km "\C-c\C-ep" 'bibtex-Proceedings)
+    (define-key km "\C-c\C-eP" 'bibtex-PhdThesis)
+    (define-key km "\C-c\C-e\M-p" 'bibtex-Preamble)
+    (define-key km "\C-c\C-e\C-s" 'bibtex-String)
+    (define-key km "\C-c\C-e\C-t" 'bibtex-TechReport)
+    (define-key km "\C-c\C-e\C-u" 'bibtex-Unpublished)
+    km))
+
+(easy-menu-define
+ bibtex-edit-menu bibtex-mode-map "BibTeX-Edit Menu in BibTeX mode"
+ '("BibTeX-Edit"
+   ("Moving inside an Entry"
+    ["End of Field" bibtex-find-text t]
+    ["Next Field" bibtex-next-field t]
+    ["Beginning of Entry" bibtex-beginning-of-entry t]
+    ["End of Entry" bibtex-end-of-entry t])
+   ("Operating on Current Entry"
+    ["Fill Entry" bibtex-fill-entry t]
+    ["Clean Entry" bibtex-clean-entry t]
+    "--"
+    ["Kill Entry" bibtex-kill-entry t]
+    ["Copy Entry to Kill Ring" bibtex-copy-entry-as-kill t]
+    ["Paste Most Recently Killed Entry" bibtex-yank t]
+    ["Paste Previously Killed Entry" bibtex-yank-pop t]
+    "--"
+    ["Ispell Entry" bibtex-ispell-entry t]
+    ["Ispell Entry Abstract" bibtex-ispell-abstract t]
+    ["Narrow to Entry" bibtex-narrow-to-entry t]
+    "--"
+    ["View Cite Locations (RefTeX)" reftex-view-crossref-from-bibtex
+     (fboundp 'reftex-view-crossref-from-bibtex)])
+   ("Operating on Current Field"
+    ["Remove Delimiters" bibtex-remove-delimiters t]
+    ["Remove OPT or ALT Prefix" bibtex-remove-OPT-or-ALT t]
+    ["Clear Field" bibtex-empty-field t]
+    "--"
+    ["Kill Field" bibtex-kill-field t]
+    ["Copy Field to Kill Ring" bibtex-copy-field-as-kill t]
+    ["Paste Most Recently Killed Field" bibtex-yank t]
+    ["Paste Previously Killed Field" bibtex-yank-pop t]
+    "--"
+    ["Make New Field" bibtex-make-field t]
+    "--"
+    ["Snatch from Similar Following Field" bibtex-pop-next t]
+    ["Snatch from Similar Preceding Field" bibtex-pop-previous t]
+    "--"
+    ["String Complete" bibtex-complete-string t]
+    ["Key Complete" bibtex-complete-key t]
+    "--"
+    ["Help about Current Field" bibtex-print-help-message t])
+   ("Operating on Buffer or Region"
+    ["Validate Entries" bibtex-validate t]
+    ["Sort Entries" bibtex-sort-buffer t]
+    ["Reformat Entries" bibtex-reformat t]
+    ["Count Entries" bibtex-count-entries t])
+   ("Miscellaneous"
+    ["Convert Alien Buffer" bibtex-convert-alien t]
+    ["Submit Bug Report" bibtex-submit-bug-report t])))
+
+(easy-menu-define
+ bibtex-entry-menu bibtex-mode-map "Entry-Types Menu in BibTeX mode"
+ (list "Entry-Types"
+       ["Article in Journal" bibtex-Article t]
+       ["Article in Conference Proceedings" bibtex-InProceedings t]
+       ["Article in a Collection" bibtex-InCollection t]
+       ["Chapter or Pages in a Book" bibtex-InBook t]
+       ["Conference Proceedings" bibtex-Proceedings t]
+       ["Book" bibtex-Book t]
+       ["Booklet (Bound, but no Publisher/Institution)" bibtex-Booklet t]
+       ["PhD. Thesis" bibtex-PhdThesis t]
+       ["Master's Thesis" bibtex-MastersThesis t]
+       ["Technical Report" bibtex-TechReport t]
+       ["Technical Manual" bibtex-Manual t]
+       ["Unpublished" bibtex-Unpublished t]
+       ["Miscellaneous" bibtex-Misc t]
+       ["String" bibtex-String t]
+       ["Preamble" bibtex-Preamble t]))
+
+\f
+;; Internal Variables
+
+(defvar bibtex-pop-previous-search-point nil)
+;; Next point where bibtex-pop-previous starts looking for a similar
+;; entry.
+
+(defvar bibtex-pop-next-search-point nil)
+;; Next point where bibtex-pop-next starts looking for a similar entry.
+
+(defvar bibtex-field-kill-ring nil)
+;; Ring of least recently killed fields. At most
+;; bibtex-field-kill-ring-max items are kept here.
+
+(defvar bibtex-field-kill-ring-yank-pointer nil)
+;; The tail of bibtex-field-kill-ring whose car is the last item yanked.
+
+(defvar bibtex-entry-kill-ring nil)
+;; Ring of least recently killed entries. At most
+;; bibtex-entry-kill-ring-max items are kept here.
+
+(defvar bibtex-entry-kill-ring-yank-pointer nil)
+;; The tail of bibtex-entry-kill-ring whose car is the last item yanked.
+
+(defvar bibtex-last-kill-command nil)
+;; Holds the type of the last kill command (either 'field or 'entry)
+
+(defvar bibtex-strings nil)
+;; Candidates for bibtex-complete-string. Initialized from
+;; bibtex-predefined-strings and bibtex-string-files.
+(make-variable-buffer-local 'bibtex-strings)
+
+(defvar bibtex-reference-keys nil)
+;; Candidates for TAB completion when entering a reference key using
+;; the minibuffer. Also used for bibtex-complete-key. Initialized in
+;; bibtex-mode and updated for each new entry.
+(make-variable-buffer-local 'bibtex-reference-keys)
+
+(defvar bibtex-buffer-last-parsed-tick nil)
+;; Remembers the value returned by buffer-modified-tick when buffer
+;; was parsed for keys the last time.
+(make-variable-buffer-local 'bibtex-buffer-last-parsed-tick)
+
+(defvar bibtex-parse-idle-timer nil)
+;; Stores if timer is already installed
+
+(defvar bibtex-progress-lastperc nil)
+;; Holds the last reported percentage for the progress message
+
+(defvar bibtex-progress-lastmes nil)
+;; Holds the last reported progress message
+
+(defvar bibtex-progress-interval nil)
+;; Holds the chosen interval
+
+(defvar bibtex-key-history nil)
+;; Used to store the history list for reading keys
+
+(defvar bibtex-entry-type-history nil)
+;; Used to store the history list for reading entry types
+
+(defvar bibtex-field-history nil)
+;; Used to store the history list for reading field names
+
+(defvar bibtex-reformat-previous-options nil)
+;; Used to store the last reformat options given
+
+(defvar bibtex-reformat-previous-reference-keys nil)
+;; Used to store the last reformat reference keys option given
+
+\f
+;; Functions to Parse the BibTeX Entries
+
+(defconst bibtex-field-name "[^\"#%'(),={} \t\n0-9][^\"#%'(),={} \t\n]*")
+;; Regexp defining the name part of a BibTeX field.
+
+(defconst bibtex-entry-type (concat "@" bibtex-field-name))
+;; Regexp defining the type part of a BibTeX entry.
+
+(defconst bibtex-reference-key "[][a-zA-Z0-9.:;?!`'/*@+=|()<>&_^$-]+")
+;; Regexp defining the reference key part of a BibTeX entry
+
+(defun bibtex-parse-nested-braces (nesting-level)
+  "*Starting on an opening brace, find the corresponding closing brace.
+When the function is called, NESTING-LEVEL has to be set to `0'."
+  (cond ((looking-at "{")
+        (search-forward-regexp "{[^{}]*")
+        (bibtex-parse-nested-braces (+ nesting-level 1)))
+       ((looking-at "}")
+        (forward-char 1)
+        (if (= nesting-level 1)
+            (point)
+          (search-forward-regexp "[^{}]*")
+          (bibtex-parse-nested-braces (- nesting-level 1))))
+       (t nil)))
+
+(defun bibtex-parse-field-string-braced ()
+  "*Parse a field string enclosed by braces.
+The field string has to be syntactically correct, which means that the number
+of opening and closing braces has to match.  If this is the case, a pair
+containing the start and end position of the field string is returned, nil
+otherwise."
+  (save-match-data
+    (let ((starting-point (point))
+         (end-point nil))
+      (if (looking-at "{")
+         (setq end-point (bibtex-parse-nested-braces 0)))
+      (goto-char starting-point)
+      (if end-point
+         (cons starting-point end-point)
+       nil))))
+
+(defun bibtex-parse-quoted-string ()
+  "*Starting on an opening quote, find the corresponding closing quote."
+  (let ((rx (concat "\""
+                       "\\("
+                           "[^\"\\]"               ;; anything but quote or backslash
+                           "\\|"
+                           "\\("
+                               "\\\\\\(.\\|\n\\)"  ;; any backslash quoted character
+                           "\\)"
+                       "\\)*"
+                   "\"")))
+    (if (looking-at rx)
+       (search-forward-regexp rx nil t)
+      nil)))
+
+(defun bibtex-parse-field-string-quoted ()
+  "*Parse a field string enclosed by quotes.
+If a syntactically correct string is found, a pair containing the start and
+end position of the field string is returned, nil otherwise."
+  (save-match-data
+    (let ((starting-point (point))
+         (end-point nil))
+      (if (looking-at "\"")
+         (setq end-point (bibtex-parse-quoted-string)))
+      (goto-char starting-point)
+      (if end-point
+         (cons starting-point end-point)
+       nil))))
+
+(defun bibtex-parse-field-string ()
+  "*Parse a field string enclosed by braces or quotes.
+If a syntactically correct string is found, a pair containing the start and
+end position of the field string is returned, nil otherwise."
+  (save-match-data
+    (let ((starting-point (point))
+         (boundaries (or (bibtex-parse-field-string-braced)
+                         (bibtex-parse-field-string-quoted))))
+      (goto-char starting-point)
+      boundaries)))
+
+(defun bibtex-search-forward-field-string (bound)
+  "*Search forward to find a field string enclosed by braces or quotes.
+If a syntactically correct string is found, a pair containing the start and
+end position of the field string is returned, nil otherwise.  The search is
+delimited by BOUND."
+  (save-match-data
+    (let ((starting-point (point))
+         (boundaries nil))
+      (while (and (not boundaries) (< (point) bound))
+       (if (search-forward-regexp "[{\"]" bound 'move)
+           (progn
+             (goto-char (match-beginning 0))
+             (let ((temp-boundaries (or (bibtex-parse-field-string-braced)
+                                        (bibtex-parse-field-string-quoted))))
+               (if (and temp-boundaries (<= (cdr temp-boundaries) bound))
+                   (setq boundaries temp-boundaries)
+                 (forward-char 1))))))
+      (goto-char starting-point)
+      boundaries)))
+
+(defun bibtex-parse-association (parse-lhs parse-rhs)
+  "*Parse a string of the format <left hand side = right-hand-side>.
+The functions PARSE-LHS and PARSE-RHS are used to parse the corresponding
+substrings.  These functions are expected to return nil if parsing is not
+successfull.  If both functions return non-nil, a pair containing the returned
+values of the functions PARSE-LHS and PARSE-RHSis returned."
+  (save-match-data
+    (let ((starting-point (point))
+         (left (funcall parse-lhs))
+         (right nil))
+      (if (and left (looking-at "[ \t\n]*=[ \t\n]*"))
+         (progn
+           (goto-char (match-end 0))
+           (setq right (funcall parse-rhs))))
+      (goto-char starting-point)
+      (if (and left right)
+         (cons left right)
+       nil))))
+
+(defvar bibtex-field-name-for-parsing nil)
+;; Temporary variable storing the name string to be parsed by the callback
+;; function bibtex-parse-field-name.
+(make-variable-buffer-local 'bibtex-field-name-for-parsing)
+
+(defun bibtex-parse-field-name ()
+  "*Parse the field name stored in bibtex-field-name-for-parsing.
+If the field name is found, return a triple consisting of the position of the
+very first character of the match, the actual starting position of the name
+part and end position of the match."
+  (if (looking-at ",[ \t\n]*")
+      (let ((start (point)))
+       (goto-char (match-end 0))
+       (if (looking-at bibtex-field-name-for-parsing)
+           (let ((boundaries (list start (match-beginning 0) (match-end 0))))
+             (goto-char (match-end 0))
+             boundaries)))))
+
+(defconst bibtex-field-const "[][a-zA-Z0-9.:;?!`'/*@+=|<>&_^$-]+")
+;; Regexp defining a bibtex field constant
+
+(defun bibtex-parse-field-text ()
+  "*Parse the text part of a BibTeX field.
+The text part is either a string, or an empty string, or a constant followed
+by one or more <# (string|constant)> pairs.  If a syntactically correct text
+is found, a pair containing the start and end position of the text is
+returned, nil otherwise."
+  (let ((starting-point (point))
+       (end-point nil)
+       (failure nil))
+    (while (and (not end-point) (not failure))
+      (if (looking-at bibtex-field-const)
+         (goto-char (match-end 0))
+       (let ((boundaries (bibtex-parse-field-string)))
+         (if boundaries
+             (goto-char (cdr boundaries))
+           (setq failure t))))
+      (if (not (looking-at "[ \t\n]*#[ \t\n]*"))
+         (setq end-point (point))
+       (goto-char (match-end 0))))
+    (if (and (not failure) end-point)
+       (cons starting-point end-point)
+      nil)))
+
+(defun bibtex-parse-field (name)
+  "*Parse a BibTeX field of regexp NAME.
+If a syntactically correct field is found, a pair containing the boundaries of
+the name and text parts of the field is returned."
+  (setq bibtex-field-name-for-parsing name)
+  (bibtex-parse-association 'bibtex-parse-field-name
+                           'bibtex-parse-field-text))
+
+(defun bibtex-search-forward-field (name bound)
+  "*Search forward to find a field of name NAME.
+If a syntactically correct field is found, a pair containing the boundaries of
+the name and text parts of the field is returned.  The search is limited by
+BOUND."
+  (save-match-data
+    (setq bibtex-field-name-for-parsing name)
+    (let ((starting-point (point))
+         (boundaries nil))
+      (while (and (not boundaries)
+                 (< (point) bound)
+                 (search-forward "," bound t))
+       (goto-char (match-beginning 0))
+       (let ((temp-boundaries
+              (bibtex-parse-association 'bibtex-parse-field-name
+                                        'bibtex-parse-field-text)))
+         (if (and temp-boundaries (<= (cdr (cdr temp-boundaries)) bound))
+             (setq boundaries temp-boundaries)
+           (forward-char 1))))
+      (goto-char starting-point)
+      boundaries)))
+
+(defun bibtex-search-backward-field (name bound)
+  "*Search backward to find a field of name NAME.
+If a syntactically correct field is found, a pair containing the boundaries of
+the name and text parts of the field is returned.  The search is limited by
+BOUND."
+  (save-match-data
+    (setq bibtex-field-name-for-parsing name)
+    (let ((starting-point (point))
+         (boundaries nil))
+      (while (and (not boundaries)
+                 (>= (point) bound)
+                 (search-backward "," bound t))
+       (let ((temp-boundaries
+              (bibtex-parse-association 'bibtex-parse-field-name
+                                        'bibtex-parse-field-text)))
+         (if temp-boundaries
+             (setq boundaries temp-boundaries))))
+      (goto-char starting-point)
+      boundaries)))
+
+(defun bibtex-start-of-field (bounds)
+  (car (car bounds)))
+(defun bibtex-end-of-field (bounds)
+  (cdr (cdr bounds)))
+(defun bibtex-start-of-name-in-field (bounds)
+  (car (cdr (car bounds))))
+(defun bibtex-end-of-name-in-field (bounds)
+  (car (cdr (cdr (car bounds)))))
+(defun bibtex-start-of-text-in-field (bounds)
+  (car (cdr bounds)))
+(defun bibtex-end-of-text-in-field (bounds)
+  (cdr (cdr bounds)))
+
+(defun bibtex-parse-string-prefix ()
+  "*Parse the prefix part of a bibtex string, including the reference key.
+If the string prefix is found, return a triple consisting of the position of
+the very first character of the match, the actual starting position of the
+reference key and the end position of the match."
+  (let* ((case-fold-search t))
+    (if (looking-at "^[ \t]*@string[ \t\n]*[({][ \t\n]*")
+       (let ((start (point)))
+         (goto-char (match-end 0))
+         (if (looking-at bibtex-reference-key)
+             (let ((boundaries (list start (match-beginning 0) (match-end 0))))
+               (goto-char (match-end 0))
+               boundaries))))))
+
+(defun bibtex-parse-string-postfix ()
+  "*Parse the postfix part of a bibtex string, including the text.
+If the string postfix is found, return a triple consisting of the position of
+the actual starting and ending position of the text and the very last
+character of the string entry."
+  (let* ((case-fold-search t)
+        (text-boundaries (bibtex-parse-field-text)))
+    (if text-boundaries
+       (progn
+         (goto-char (cdr text-boundaries))
+         (if (looking-at "[ \t\n]*[})]")
+             (let ((boundaries (list (car text-boundaries)
+                                     (cdr text-boundaries)
+                                     (match-end 0))))
+               (goto-char (match-end 0))
+               boundaries))))))
+
+(defun bibtex-parse-string ()
+  "*Parse a BibTeX string entry.
+If a syntactically correct entry is found, a pair containing the boundaries of
+the reference key and text parts of the entry is returned."
+  (bibtex-parse-association 'bibtex-parse-string-prefix
+                           'bibtex-parse-string-postfix))
+
+(defun bibtex-search-forward-string ()
+  "*Search forward to find a bibtex string entry.
+If a syntactically correct entry is found, a pair containing the boundaries of
+the reference key and text parts of the string is returned."
+  (save-match-data
+    (let* ((case-fold-search t)
+          (starting-point (point))
+          (boundaries nil))
+      (while (and (not boundaries)
+                 (search-forward-regexp
+                  "^[ \t]*@string[ \t\n]*[({][ \t\n]*" nil t))
+       (goto-char (match-beginning 0))
+       (let ((temp-boundaries (bibtex-parse-string)))
+         (if temp-boundaries
+             (setq boundaries temp-boundaries)
+           (forward-char 1))))
+      (goto-char starting-point)
+      boundaries)))
+
+(defun bibtex-search-backward-string ()
+  "*Search backward to find a bibtex string entry.
+If a syntactically correct entry is found, a pair containing the boundaries of
+the reference key and text parts of the field is returned."
+  (save-match-data
+    (let* ((case-fold-search t)
+          (starting-point (point))
+          (boundaries nil))
+      (while (and (not boundaries)
+                 (search-backward-regexp
+                  "^[ \t]*@string[ \t\n]*[({][ \t\n]*" nil t))
+       (goto-char (match-beginning 0))
+       (let ((temp-boundaries (bibtex-parse-string)))
+         (if temp-boundaries
+             (setq boundaries temp-boundaries))))
+      (goto-char starting-point)
+      boundaries)))
+
+(defun bibtex-end-of-string (bounds)
+  (car (cdr (cdr (cdr bounds)))))
+(defun bibtex-start-of-reference-key-in-string (bounds)
+  (car (cdr (car bounds))))
+(defun bibtex-end-of-reference-key-in-string (bounds)
+  (car (cdr (cdr (car bounds)))))
+(defun bibtex-start-of-text-in-string (bounds)
+  (car (cdr bounds)))
+(defun bibtex-end-of-text-in-string (bounds)
+  (car (cdr (cdr bounds))))
+
+(defconst bibtex-entry-head
+  (concat "^[ \t]*\\("
+         bibtex-entry-type
+         "\\)[ \t]*[({][ \t\n]*\\("
+         bibtex-reference-key
+         "\\)"))
+;; Regexp defining format of the header line of a BibTeX entry.
+
+(defconst bibtex-entry-maybe-empty-head
+  (concat bibtex-entry-head "?"))
+;; Regexp defining format of the header line of a maybe empty
+;; BibTeX entry (possibly without reference key).
+
+(defconst bibtex-type-in-head 1)
+;; The regexp subexpression number of the type part in
+;; bibtex-entry-head.
+
+(defconst bibtex-key-in-head 2)
+;; The regexp subexpression number of the key part in
+;; bibtex-entry-head.
+
+(defconst bibtex-entry-postfix "[ \t\n]*,?[ \t\n]*[})]")
+;; Regexp defining the postfix of a bibtex entry
+
+(defconst bibtex-key-in-entry bibtex-key-in-head)
+;; The regexp subexpression number of the key part in a bibtex entry.
+
+(defvar bibtex-font-lock-keywords
+  (list
+   ;; entry type and reference key
+   (list bibtex-entry-maybe-empty-head
+         (list bibtex-type-in-head 'font-lock-function-name-face)
+         (list bibtex-key-in-head 'font-lock-constant-face nil t))
+   ;; comments
+   (list
+    (concat "^\\([ \t]*" bibtex-comment-start ".*\\)$")
+    1 'font-lock-comment-face)
+   ;; optional field names (treated as comments)
+   (list
+    (concat "^[ \t]*\\(OPT" bibtex-field-name "\\)[ \t]*=")
+    1 'font-lock-comment-face)
+   ;; field names
+   (list (concat "^[ \t]*\\(" bibtex-field-name "\\)[ \t]*=")
+         1 'font-lock-variable-name-face)
+   "*Default expressions to highlight in BibTeX mode."))
+;; now all needed patterns are defined
+
+
+\f
+;; Helper Functions
+
+(defun bibtex-delete-whitespace ()
+  ;; Delete all whitespace starting at point
+  (if (looking-at "[ \t\n]+")
+      (delete-region (point) (match-end 0))))
+
+(defun bibtex-current-line ()
+  ;; this computes line number of point regardless whether the buffer
+  ;; is narrowed
+  (+ (count-lines 1 (point))
+     (if (equal (current-column) 0) 1 0)))
+
+(defun bibtex-member-of-regexp (string list)
+  ;; Return non-nil if STRING is exactly matched by an element of
+  ;; LIST. The value is actually the tail of LIST whose
+  ;; car matches STRING.
+  (let* (case-fold-search)
+    (while
+        (and list (not (string-match (concat "^" (car list) "$") string)))
+      (setq list (cdr list)))
+    list))
+
+(defun bibtex-assoc-of-regexp (string alist)
+  ;; Return non-nil if STRING is exactly matched by the car of an
+  ;; element of LIST (case ignored). The value is actually the element
+  ;; of LIST whose car matches STRING.
+  (let* ((case-fold-search t))
+    (while
+        (and alist
+             (not (string-match (concat "^" (car (car alist)) "$") string)))
+      (setq alist (cdr alist)))
+    (car alist)))
+
+(defun bibtex-skip-to-valid-entry (&optional backward)
+  ;; If not at beginning of valid BibTeX entry, move to beginning of
+  ;; the next valid one. With argument backward non-nil, move backward
+  ;; to beginning of previous valid one. A valid entry is a
+  ;; syntactical correct one with type contained in
+  ;; bibtex-entry-field-alist or, if bibtex-sort-ignore-string-entries
+  ;; is nil, a syntactical correct string entry.
+  (let* ((case-fold-search t)
+        (valid-bibtex-entry
+         (concat
+          "@[ \t]*\\("
+          (mapconcat
+           (lambda (type)
+             (concat "\\(" (car type) "\\)"))
+           bibtex-entry-field-alist
+           "\\|")
+          "\\)"))
+        found)
+    (while (and (not found)
+                (not (if backward
+                         (bobp)
+                       (eobp))))
+      (let ((pnt (point)))
+        (cond
+         ((looking-at valid-bibtex-entry)
+          (if (and
+               (bibtex-search-entry nil nil t)
+               (equal (match-beginning 0) pnt))
+              (setq found t)))
+         ((and (not bibtex-sort-ignore-string-entries)
+               (bibtex-parse-string))
+          (setq found t)))
+        (if found
+            (goto-char pnt)
+          (if backward
+              (progn
+                (goto-char (1- pnt))
+                (if (re-search-backward "^[ \t]*\\(@\\)" nil 'move)
+                    (goto-char (match-beginning 1))))
+            (goto-char (1+ pnt))
+            (if (re-search-forward "^[ \t]*@" nil 'move)
+                (forward-char -1))))))))
+
+(defun bibtex-map-entries (fun)
+  ;; Call FUN for each BibTeX entry starting with the current. Do this
+  ;; to the end of the file. FUN is called with one argument, the key
+  ;; of the entry, and with point inside the entry. If
+  ;; bibtex-sort-ignore-string-entries is non-nil, FUN will not be
+  ;; called for @String entries.
+  (let* ((case-fold-search t))
+    (bibtex-beginning-of-entry)
+    (while (re-search-forward bibtex-entry-maybe-empty-head nil t)
+      (let ((pnt (point))
+            (entry-type
+             (downcase (buffer-substring-no-properties
+                        (1+ (match-beginning bibtex-type-in-head))
+                        (match-end bibtex-type-in-head))))
+            (reference-key
+             (if (match-beginning bibtex-key-in-head)
+                 (buffer-substring-no-properties
+                  (match-beginning bibtex-key-in-head)
+                  (match-end bibtex-key-in-head))
+               "")))
+        (if (or
+             (and
+              (not bibtex-sort-ignore-string-entries)
+              (string-equal "string" (downcase entry-type)))
+             (assoc-ignore-case entry-type bibtex-entry-field-alist))
+            (funcall fun reference-key))
+        (goto-char pnt)
+        (bibtex-end-of-entry)))))
+
+(defun bibtex-progress-message (&optional flag interval)
+  ;; echos a message about progress of current buffer
+  ;; if flag is a string, the message is initialized (in this case a
+  ;; value for INTERVAL may be given as well (if not this is set to 5))
+  ;; if flag is done, the message is deinitialized
+  ;; if flag is absent, a message is echoed if point was incremented
+  ;; at least INTERVAL percent since last message was echoed
+  (let* ((size (- (point-max) (point-min)))
+         (perc (if (= size 0)
+                   100
+                 (/ (* 100 (- (point) (point-min))) size))))
+    (if (or (and (not flag)
+                 (>= perc
+                     (+ bibtex-progress-interval bibtex-progress-lastperc)))
+            (stringp flag))
+        (progn
+          (if (stringp flag)
+              (progn
+                (setq bibtex-progress-lastmes flag)
+                (if interval
+                    (setq bibtex-progress-interval interval)
+                  (setq bibtex-progress-interval 5))))
+          (setq bibtex-progress-lastperc perc)
+          (message (concat bibtex-progress-lastmes " (%d%%)") perc))
+      (if (equal flag 'done)
+          (progn
+            (message (concat bibtex-progress-lastmes " (done)"))
+            (setq bibtex-progress-lastmes nil))))))
+
+
+(defun bibtex-field-left-delimiter ()
+  ;; returns a string dependent on bibtex-field-delimiters
+  (if (equal bibtex-field-delimiters 'braces)
+      "{"
+    "\""))
+
+(defun bibtex-field-right-delimiter ()
+  ;; returns a string dependent on bibtex-field-delimiters
+  (if (equal bibtex-field-delimiters 'braces)
+      "}"
+    "\""))
+
+(defun bibtex-entry-left-delimiter ()
+  ;; returns a string dependent on bibtex-field-delimiters
+  (if (equal bibtex-entry-delimiters 'braces)
+      "{"
+    "("))
+
+(defun bibtex-entry-right-delimiter ()
+  ;; returns a string dependent on bibtex-field-delimiters
+  (if (equal bibtex-entry-delimiters 'braces)
+      "}"
+    ")"))
+
+(defun bibtex-search-entry
+  (empty-head &optional bound noerror backward)
+  ;; A helper function necessary since the failure stack size limit for
+  ;; regexps was reduced in emacs 19.32.
+  ;; It searches for a BibTeX entry (maybe without a reference key if
+  ;; EMPTY-HEAD is t).
+  ;; BOUND and NOERROR are exactly as in re-search-forward. If
+  ;; BACKWARD is non-nil, search is done in reverse direction. After
+  ;; call to this function MATCH-BEGINNING and MATCH-END functions are
+  ;; defined, but only for the head part of the entry (especially
+  ;; (match-end 0) just gives the end of the head part).
+  (let ((pnt (point))
+        (prefix (if empty-head
+                    bibtex-entry-maybe-empty-head
+                  bibtex-entry-head)))
+    (if backward
+        (let (found)
+          (while (and (not found)
+                      (re-search-backward prefix bound noerror))
+            (setq found (bibtex-search-entry empty-head pnt t)))
+          (if found
+              (goto-char (match-beginning 0))
+            (if (equal noerror nil)
+                ;; yell
+                (error "Search of BibTeX entry failed"))
+            (if (equal noerror t)
+                ;; don't move
+                (goto-char pnt))
+            nil))
+      (let ((limit (if bound bound (point-max)))
+            md
+            found)
+        (while (and (not found)
+                    (re-search-forward prefix bound noerror))
+          (setq md (match-data))
+          ;; save match-data of prefix regexp
+          (let ((entry-closer
+                 (if (save-excursion
+                       (goto-char (match-end bibtex-type-in-head))
+                       (looking-at "[ \t]*("))
+                     ;; entry opened with parenthesis
+                     ")"
+                   "}")))
+           (let ((infix-start (point))
+                 (finished nil))
+             (while (not finished)
+               (if (and (looking-at "[ \t\n]*")
+                        (<= (match-end 0) limit))
+                   (goto-char (match-end 0)))
+               (let ((bounds (bibtex-parse-field bibtex-field-name)))
+                 (if (and bounds (<= (bibtex-end-of-field bounds) limit))
+                     (progn
+                       (goto-char (bibtex-end-of-field bounds))
+                       (setq infix-start (point)))
+                   (goto-char infix-start)
+                   (setq finished t)))))
+            ;; This matches the infix* part. The AND construction assures
+            ;; that BOUND is respected.
+            (if (and (looking-at bibtex-entry-postfix)
+                     (string-equal
+                      (buffer-substring-no-properties
+                       (1- (match-end 0)) (match-end 0))
+                      entry-closer)
+                     (<= (match-end 0) limit))
+                (progn
+                  (re-search-forward bibtex-entry-postfix)
+                  (setq found t)))))
+        (if found
+            (progn
+              (set-match-data md)
+              ;; to set match-beginning/end again
+              (point))
+          (if (equal noerror nil)
+              ;; yell
+              (error "Search of BibTeX entry failed"))
+          (if (equal noerror t)
+              ;; don't move
+              (goto-char pnt))
+          nil)))))
+
+(defun bibtex-flash-head ()
+  ;; Flash at BibTeX entry head before point, if exists.
+  (let* ((case-fold-search t)
+        flash)
+    (cond ((re-search-backward bibtex-entry-head nil t)
+          (goto-char (match-beginning bibtex-type-in-head))
+          (setq flash (match-end bibtex-key-in-entry)))
+         (t
+          (end-of-line)
+          (skip-chars-backward " \t")
+          (setq flash (point))
+          (beginning-of-line)
+          (skip-chars-forward " \t")))
+    (if (pos-visible-in-window-p (point))
+       (sit-for 1)
+      (message "From: %s"
+              (buffer-substring (point) flash)))))
+
+(defun bibtex-make-optional-field (e-t)
+  "Makes an optional field named E-T in current BibTeX entry."
+  (if (consp e-t)
+      (bibtex-make-field (cons (concat "OPT" (car e-t)) (cdr e-t)))
+    (bibtex-make-field (concat "OPT" e-t))))
+
+(defun bibtex-move-outside-of-entry ()
+  ;; Make sure we are outside of a BibTeX entry.
+  (let ((orig-point (point)))
+    (bibtex-end-of-entry)
+    (if (< (point) orig-point)
+        ;; We moved backward, so we weren't inside an entry to begin with.
+        ;; Leave point at the beginning of a line, and preferably
+        ;; at the beginning of a paragraph.
+        (progn
+          (goto-char orig-point)
+          (beginning-of-line 1)
+          (if (not (= ?\n (char-before (1- (point)))))
+              (progn
+                (re-search-forward "^[ \t]*[@\n]" nil 'move)
+                (backward-char 1)))))
+    (skip-chars-forward " \t\n")))
+
+(defun bibtex-beginning-of-first-entry ()
+  ;; Go to the beginning of the first BibTeX entry in buffer. Return
+  ;; point.
+  (goto-char (point-min))
+  (if (re-search-forward "^[ \t]*@" nil 'move)
+      (beginning-of-line))
+  (point))
+
+(defun bibtex-beginning-of-last-entry ()
+  ;; Go to the beginning of the last BibTeX entry in buffer.
+  (goto-char (point-max))
+  (if (re-search-backward "^[ \t]*@" nil 'move)
+      (beginning-of-line))
+  (point))
+
+(defun bibtex-inside-field ()
+  ;; Try to avoid point being at end of a BibTeX field.
+  (end-of-line)
+  (skip-chars-backward " \t")
+  (cond ((= (preceding-char) ?,)
+        (forward-char -2)))
+  (cond ((or
+          (= (preceding-char) ?})
+          (= (preceding-char) ?\"))
+         (forward-char -1))))
+
+(defun bibtex-enclosing-field (&optional noerr)
+  ;; Search for BibTeX field enclosing point. Point moves to end of
+  ;; field. Use match-beginning and match-end to parse the field. If
+  ;; NOERR is non-nil, no error is signalled. In this case, t is
+  ;; returned on success, nil otherwise.
+  (let* ((case-fold-search t)
+        (old-point (point))
+        (boe (bibtex-beginning-of-entry)))
+    (goto-char old-point)
+    (let ((bounds (bibtex-search-backward-field bibtex-field-name boe)))
+      (if (and bounds
+              (<= (bibtex-start-of-field bounds) old-point)
+              (>= (bibtex-end-of-field bounds) old-point))
+         bounds
+       (if noerr
+           nil
+         (error "Can't find enclosing BibTeX field"))))))
+
+(defun bibtex-enclosing-entry-maybe-empty-head ()
+  ;; Search for BibTeX entry enclosing point. Point moves to
+  ;; end of entry. Beginning (but not end) of entry is given
+  ;; by (match-beginning 0).
+  (let* ((case-fold-search t)
+        (old-point (point)))
+    (if (not
+         (re-search-backward
+          bibtex-entry-maybe-empty-head nil t))
+        (progn
+          (error "Can't find enclosing BibTeX entry")
+          (goto-char old-point)))
+    (goto-char (match-beginning bibtex-type-in-head))
+    (if (not
+         (bibtex-search-entry t nil t))
+        (progn
+          (error "Can't find enclosing BibTeX entry")
+          (goto-char old-point)))))
+
+(defun bibtex-insert-current-kill (n)
+  (if (not bibtex-last-kill-command)
+      (error "BibTeX kill ring is empty")
+    (let* ((kr (if (equal bibtex-last-kill-command 'field)
+                   'bibtex-field-kill-ring
+                 'bibtex-entry-kill-ring))
+           (kryp (if (equal bibtex-last-kill-command 'field)
+                     'bibtex-field-kill-ring-yank-pointer
+                   'bibtex-entry-kill-ring-yank-pointer))
+           (ARGth-kill-element
+            (nthcdr
+             (mod (- n (length (eval kryp))) (length (eval kr)))
+             (eval kr)))
+           (current (car (set kryp ARGth-kill-element))))
+      (cond
+       ((equal bibtex-last-kill-command 'field)
+        (let (bibtex-help-message)
+          (bibtex-find-text nil t)
+          (if (looking-at "[}\"]")
+              (forward-char)))
+        (set-mark (point))
+        (message "Mark set")
+        (bibtex-make-field (list (elt current 1) nil (elt current 2)) t))
+       ((equal bibtex-last-kill-command 'entry)
+        (if (not (eobp))
+            (bibtex-beginning-of-entry))
+        (set-mark (point))
+        (message "Mark set")
+        (insert (elt current 1)))
+       (t
+        (error
+         "Unknown tag field: %s.  Please submit a bug report"
+         bibtex-last-kill-command))))))
+
+(defun bibtex-format-field-delimiters (start stop)
+  "*Replaces delimiters for field strings between START and STOP.
+If the current delimiters equal the new delimiters, the buffer is not
+changed."
+  (goto-char start)
+  (let ((boundaries (bibtex-search-forward-field-string stop)))
+    (while boundaries
+      (goto-char (car boundaries))
+      (if (not (looking-at (bibtex-field-left-delimiter)))
+         (progn
+           (delete-char 1)
+           (insert (bibtex-field-left-delimiter))))
+      (goto-char (- (cdr boundaries) 1))
+      (if (not (looking-at (bibtex-field-right-delimiter)))
+         (progn
+           (delete-char 1)
+           (insert (bibtex-field-right-delimiter))))
+      (setq boundaries (bibtex-search-forward-field-string stop)))))
+
+(defun bibtex-format-entry ()
+  ;; Helper function for bibtex-clean-entry. Formats current entry
+  ;; according to variable bibtex-entry-format.
+  (let* ((case-fold-search t)
+        (beg (point))
+        (start (bibtex-beginning-of-entry))
+        crossref-there
+        alternatives-there
+        non-empty-alternative)
+    (let ((end (copy-marker (bibtex-end-of-entry))))
+      (if (equal start (marker-position end))
+          (error "Not on a known BibTeX entry")
+        (goto-char start)
+       (let ((bounds (bibtex-search-forward-field bibtex-field-name end)))
+         (while bounds
+           ;; determine if entry has crossref field and if at least
+           ;; one alternative is non-empty
+           (let ((begin-name (bibtex-start-of-name-in-field bounds))
+                 (end-name (bibtex-end-of-name-in-field bounds))
+                 (begin-text (bibtex-start-of-text-in-field bounds))
+                 (end-text (bibtex-end-of-text-in-field bounds)))
+             (goto-char begin-name)
+             (if (looking-at "ALT")
+                 (progn
+                   (setq alternatives-there t)
+                   (goto-char begin-text)
+                   (if (not (looking-at "\\(\"\"\\)\\|\\({}\\)"))
+                       (setq non-empty-alternative t))))
+             (if (string-match
+                  "\\(OPT\\)?crossref"
+                  (buffer-substring-no-properties begin-name end-name))
+                 (progn
+                   (setq
+                    crossref-there
+                    (buffer-substring-no-properties
+                     (1+ begin-text) (1- end-text)))
+                   (if (equal crossref-there "")
+                       (setq crossref-there nil)))))
+           (goto-char (bibtex-end-of-field bounds))
+           (setq bounds (bibtex-search-forward-field bibtex-field-name end))))
+        (if (and alternatives-there
+                 (not non-empty-alternative))
+            (progn
+              (goto-char beg)
+              (error "All alternatives are empty")))
+        (goto-char start)
+        (re-search-forward bibtex-entry-type end)
+        (let* ((begin-type (1+ (match-beginning 0)))
+               (end-type (match-end 0))
+               (entry-type
+                (downcase
+                 (buffer-substring-no-properties begin-type end-type)))
+               (entry-list
+                (assoc-ignore-case entry-type bibtex-entry-field-alist))
+               (req (elt (elt entry-list 1) 0))
+               (creq (elt (elt entry-list 2) 0))
+               (format (if (equal bibtex-entry-format t)
+                           '(realign opts-or-alts numerical-fields
+                                     last-comma page-dashes delimiters
+                                     unify-case inherit-booktitle)
+                         bibtex-entry-format))
+               field-done)
+          (if (memq 'unify-case format)
+              (progn
+                (delete-region begin-type end-type)
+                (insert (car entry-list))))
+          (if (memq 'delimiters format)
+              (progn
+                (goto-char end-type)
+                (skip-chars-forward " \t\n")
+                (delete-char 1)
+                (insert (bibtex-entry-left-delimiter))))
+          (goto-char start)
+          (let ((bounds (bibtex-search-forward-field bibtex-field-name end)))
+           (while bounds
+             (let* ((begin-field (copy-marker (bibtex-start-of-field bounds)))
+                    (end-field (copy-marker (bibtex-end-of-field bounds)))
+                    (begin-name (copy-marker (bibtex-start-of-name-in-field bounds)))
+                    (end-name (copy-marker (bibtex-end-of-name-in-field bounds)))
+                    (begin-text (copy-marker (bibtex-start-of-text-in-field bounds)))
+                    (end-text (copy-marker (bibtex-end-of-text-in-field bounds)))
+                    (field-name
+                     (buffer-substring-no-properties
+                      (if (string-match
+                           "^\\(OPT\\)\\|\\(ALT\\)$"
+                           (buffer-substring-no-properties
+                            begin-name (+ begin-name 3)))
+                          (+ begin-name 3)
+                        begin-name)
+                      end-name)))
+               (cond
+                ((and
+                  (memq 'opts-or-alts format)
+                  (progn (goto-char begin-name)
+                         (looking-at "OPT\\|ALT")))
+                 (goto-char begin-text)
+                 (if (looking-at "\\(\"\"\\)\\|\\({}\\)")
+                     ;; empty: delete whole field if really optional
+                     ;; (missing crossref handled) or complain
+                     (if (and
+                          (progn
+                            (goto-char begin-name)
+                            (looking-at "OPT"))
+                          (not crossref-there)
+                          (assoc-ignore-case field-name req))
+                         ;; field is not really optional
+                         (progn
+                           (goto-char begin-name)
+                           (bibtex-remove-OPT-or-ALT)
+                           (error
+                            "Mandatory field ``%s'' is empty" field-name))
+                       ;; field is optional
+                       (delete-region begin-field end-field))
+                   ;; otherwise: not empty, delete "OPT"
+                   (goto-char begin-name)
+                   (bibtex-remove-OPT-or-ALT)))
+                ((and
+                  (memq 'numerical-fields format)
+                  (progn
+                    (goto-char begin-text)
+                    (looking-at "\\(\"[0-9]+\"\\)\\|\\({[0-9]+}\\)")))
+                 (goto-char end-text)
+                 (delete-char -1)
+                 (goto-char begin-text)
+                 (delete-char 1))
+                (t
+                 (if (memq 'delimiters format)
+                     (bibtex-format-field-delimiters begin-text end-text))
+                 (if (and
+                      (memq 'page-dashes format)
+                      (string-match "^\\(OPT\\)?pages$" (downcase field-name))
+                      (progn
+                        (goto-char begin-text)
+                        (looking-at
+                         "\\([\"{][0-9]+\\)[ \t\n]*--?[ \t\n]*\\([0-9]+[\"}]\\)")))
+                     (replace-match "\\1-\\2"))
+                 (if (and
+                      (memq 'inherit-booktitle format)
+                      (equal (downcase field-name) "booktitle")
+                      (progn
+                        (goto-char begin-text)
+                        (looking-at "\\(\"\"\\)\\|\\({}\\)"))
+                      crossref-there
+                      (not (bibtex-find-entry-location crossref-there t)))
+                     ;; booktitle field empty and crossref entry found
+                     ;; --> insert title field of crossreferenced entry if there
+                     (let ((stop (bibtex-end-of-entry)))
+                       (bibtex-beginning-of-entry)
+                       (let ((bounds (bibtex-search-forward-field "title" stop)))
+                         (if bounds
+                             (progn
+                               (goto-char begin-text)
+                               (forward-char)
+                               (insert
+                                (buffer-substring-no-properties
+                                 (1+ (bibtex-start-of-text-in-field bounds))
+                                 (1- (bibtex-end-of-text-in-field bounds)))))))))
+                 (if (progn
+                       (goto-char begin-text)
+                       (looking-at "\\(\"\"\\)\\|\\({}\\)"))
+                     ;; if empty field, complain
+                     (progn
+                       (forward-char)
+                       (if (or (and
+                                crossref-there
+                                (assoc-ignore-case
+                                 field-name creq))
+                               (and
+                                (not crossref-there)
+                                (assoc-ignore-case
+                                 field-name req)))
+                           (error
+                            "Mandatory field ``%s'' is empty" field-name))))
+                 (if (memq 'unify-case format)
+                     (let* ((fl
+                             (car (cdr (assoc-ignore-case
+                                        entry-type
+                                        bibtex-entry-field-alist))))
+                            (field-list
+                             (append
+                              (elt fl 0)
+                              (elt fl 1)
+                              bibtex-user-optional-fields))
+                            (new-field-name
+                             (car
+                              (assoc-ignore-case field-name field-list))))
+                       (goto-char begin-name)
+                       (if new-field-name
+                           (progn
+                             (delete-region begin-name end-name)
+                             (insert new-field-name))
+                         (downcase-region begin-name end-name))))
+                 (setq field-done t)))
+               (if (not field-done)
+                   (goto-char begin-field)
+                 (setq field-done nil)
+                 (goto-char end-field)))
+             (setq bounds (bibtex-search-forward-field bibtex-field-name end))))
+          (if (looking-at (bibtex-field-right-delimiter))
+              (forward-char))
+          (if (memq 'last-comma format)
+              (cond ((and
+                      bibtex-comma-after-last-field
+                      (not (looking-at ",")))
+                     (insert ","))
+                    ((and
+                      (not bibtex-comma-after-last-field)
+                      (looking-at ","))
+                     (delete-char 1))))
+          (if (looking-at ",")
+              (forward-char))
+          (if (memq 'delimiters format)
+              (progn
+                (skip-chars-forward " \t\n")
+                (delete-char 1)
+                (insert (bibtex-entry-right-delimiter))))
+          (if (memq 'realign format)
+              (bibtex-fill-entry)))))))
+
+(defun bibtex-autokey-change (string change-list)
+  ;; Returns a string where some regexps are changed according to
+  ;; change-list. Every item of change-list is an (old-regexp
+  ;; new-string) pair.
+  (let* (case-fold-search
+        (return-string string)
+        (index 0)
+        (len (length change-list))
+        change-item)
+    (while (< index len)
+      (setq change-item (elt change-list index))
+      (while (string-match (car change-item) return-string)
+        (setq
+         return-string
+         (concat (substring return-string 0 (match-beginning 0))
+                 (elt change-item 1)
+                 (substring return-string (match-end 0)))))
+      (setq index (1+ index)))
+    return-string))
+
+(defun bibtex-autokey-abbrev (string len)
+  ;; Returns an abbreviation of string with at least len
+  ;; characters.  String is aborted only after a consonant or at the
+  ;; word end.  If len is not a number, string is returned unchanged.
+  (cond ((or
+          (not (numberp len))
+          (<= (length string) len))
+         string)
+        ((equal len 0)
+         "")
+        (t
+         (let* ((case-fold-search t)
+                (abort-char
+                 (string-match "[^aeiou]" string (1- len))))
+           (if abort-char
+               (substring string 0 (1+ abort-char))
+             string)))))
+
+(defun bibtex-autokey-get-namefield (min max)
+  ;; returns the contents of the name field of the current entry
+  ;; does some modifications based on `bibtex-autokey-name-change-strings'
+  ;; and removes newlines unconditionally
+  (goto-char min)
+  (let* ((case-fold-search t)
+        (author-or-editor "\\(author\\)\\|\\(editor\\)")
+        (bounds (bibtex-search-forward-field author-or-editor max)))
+    (if bounds
+        (bibtex-autokey-change
+         (buffer-substring-no-properties
+          (1+ (bibtex-start-of-text-in-field bounds))
+          (1- (bibtex-end-of-text-in-field bounds)))
+         (append bibtex-autokey-name-change-strings '(("\n" " "))))
+      "")))
+
+(defun bibtex-autokey-get-names (namefield)
+  ;; gathers all names in namefield into a list
+  (let* ((case-fold-search t)
+        names)
+    (while (not (equal namefield ""))
+      (let (name)
+        (if (string-match "[ \t\n]and[ \t\n]" namefield)
+            (setq name (substring namefield 0 (match-beginning 0))
+                  namefield (substring namefield (match-end 0)))
+          (setq name namefield
+                namefield ""))
+        (setq names (append names (list name)))))
+    names))
+
+(defun bibtex-autokey-demangle-name (fullname)
+  ;; gets the `last' part from a well-formed name
+  (let* (case-fold-search
+         (lastname
+          (if (string-match "," fullname)
+              ;; name is of the form "von Last, First" or
+              ;; "von Last, Jr, First"
+              ;; --> take only the part before the comma
+              (let ((von-last
+                     (substring fullname 0 (match-beginning 0))))
+                (if (string-match "^[a-z]" von-last)
+                    ;; von-last has a "von" part --> take the "last" part
+                    (if (string-match "[ \t][A-Z]" von-last)
+                        (substring von-last (1+ (match-beginning 0)))
+                      (error
+                       "Name %s is incorrectly formed" fullname))
+                  ;; von-last has no "von" part --> take all
+                  von-last))
+            ;; name is of the form "First von Last"
+            (if (string-match "[ \t]" fullname)
+                ;; more than one token
+                (if (string-match "[ \t][a-z]" fullname)
+                    ;; there is a "von" part
+                    ;; --> take everything after that
+                    (if (string-match
+                         "[ \t][A-Z]" fullname (match-end 0))
+                        (substring fullname (1+ (match-beginning 0)))
+                      (error
+                       "Name %s is incorrectly formed" fullname))
+                  ;; there is no "von" part --> take only the last token
+                  (if (string-match " [^ ]*$" fullname)
+                      (substring fullname (1+ (match-beginning 0)))
+                    (error "Name %s is incorrectly formed" fullname)))
+              ;; only one token --> take it
+              fullname)))
+         (usename
+          (if (string-match "[ \t]+" lastname)
+              ;; lastname consists of two or more tokens
+              ;; --> take only the first one
+              (substring lastname 0 (match-beginning 0))
+            lastname)))
+    (funcall bibtex-autokey-name-case-convert usename)))
+
+(defun bibtex-autokey-get-namelist (namefield)
+  ;; gets namefield, performs abbreviations on the last parts, and
+  ;; return results as a list
+  (mapcar
+   (lambda (fullname)
+     (setq
+      fullname (substring fullname (string-match "[^ \t]" fullname)))
+     (bibtex-autokey-abbrev
+      (bibtex-autokey-demangle-name fullname)
+      bibtex-autokey-name-length))
+   (bibtex-autokey-get-names namefield)))
+
+(defun bibtex-autokey-get-yearfield-digits (max)
+  ;; get digit substring from year field.
+  (let ((bounds (bibtex-search-forward-field "year" max)))
+    (if bounds
+       (let ((year (buffer-substring-no-properties
+                    (bibtex-start-of-text-in-field bounds)
+                    (bibtex-end-of-text-in-field bounds))))
+         (string-match "[^0-9]*\\([0-9]+\\)" year)
+         (substring year (match-beginning 1) (match-end 1)))
+      "")))
+
+(defun bibtex-autokey-get-yearfield (min max)
+  ;; get year field from current or maybe crossreferenced entry
+  (goto-char min)
+  (let* ((case-fold-search t)
+        (year (bibtex-autokey-get-yearfield-digits max)))
+    (if (and (string= year "") bibtex-autokey-year-use-crossref-entry)
+       (let* ((bounds
+               (bibtex-search-forward-field "\\(OPT\\)?crossref" max))
+              (crossref-field
+               (if bounds
+                   (buffer-substring-no-properties
+                    (1+ (bibtex-start-of-text-in-field bounds))
+                    (1- (bibtex-end-of-text-in-field bounds))))))
+         (if (not (bibtex-find-entry-location crossref-field t))
+             (let ((stop (bibtex-end-of-entry)))
+               (bibtex-beginning-of-entry)
+               (bibtex-autokey-get-yearfield-digits stop))
+           ""))
+      year)))
+
+(defun bibtex-autokey-get-titlestring (min max)
+  ;; get title field contents up to a terminator
+  (goto-char min)
+  (let* ((case-fold-search t)
+        (bounds (bibtex-search-forward-field "title" max))
+        (titlefield
+         (if bounds
+             (bibtex-autokey-change
+              (buffer-substring-no-properties
+               (1+ (bibtex-start-of-text-in-field bounds))
+               (1- (bibtex-end-of-text-in-field bounds)))
+              bibtex-autokey-titleword-change-strings)
+           ""))
+        (title-terminators bibtex-autokey-title-terminators))
+    (while (not (null title-terminators))
+      (if (string-match (car title-terminators) titlefield)
+         (setq titlefield (substring titlefield 0 (match-beginning 0))))
+      (setq title-terminators (cdr title-terminators)))
+    titlefield))
+
+(defun bibtex-autokey-get-titles (titlestring)
+  ;; gathers words from titlestring into a list. Ignores
+  ;; specific words and uses only a specific amount of words.
+  (let* (case-fold-search
+        titlewords
+        titlewords-extra
+        (counter 0))
+    (while (and
+            (not (equal titlestring ""))
+            (or
+             (not (numberp bibtex-autokey-titlewords))
+             (< counter
+                (+ bibtex-autokey-titlewords
+                   bibtex-autokey-titlewords-stretch))))
+      (if (string-match "\\b\\w+" titlestring)
+          (let* ((end-match (match-end 0))
+                 (titleword
+                 (substring titlestring (match-beginning 0) end-match)))
+           (if (bibtex-member-of-regexp
+                titleword
+                bibtex-autokey-titleword-ignore)
+               (setq counter (1- counter))
+              (setq
+              titleword
+              (funcall bibtex-autokey-titleword-case-convert titleword))
+             (if (or (not (numberp bibtex-autokey-titlewords))
+                     (< counter bibtex-autokey-titlewords))
+                 (setq titlewords (append titlewords (list titleword)))
+               (setq titlewords-extra
+                     (append titlewords-extra (list titleword)))))
+            (setq
+             titlestring (substring titlestring end-match)))
+        (setq titlestring ""))
+      (setq counter (1+ counter)))
+    (if (string-match "\\b\\w+" titlestring)
+        titlewords
+      (append titlewords titlewords-extra))))
+
+(defun bibtex-autokey-get-titlelist (titlestring)
+  ;; returns all words in titlestring as a list
+  ;; does some abbreviation on the found words
+  (mapcar
+   (lambda (titleword)
+     (let ((abbrev
+            (bibtex-assoc-of-regexp
+             titleword bibtex-autokey-titleword-abbrevs)))
+       (if abbrev
+           (elt abbrev 1)
+         (bibtex-autokey-abbrev
+          titleword
+          bibtex-autokey-titleword-length))))
+   (bibtex-autokey-get-titles titlestring)))
+
+(defun bibtex-generate-autokey ()
+  "Generates automatically a key from the author/editor and the title field.
+This will only work for entries where each field begins on a separate line.
+The generation algorithm works as follows:
+ 1. Use the value of `bibtex-autokey-prefix-string' as a prefix.
+ 2. If there is a non-empty author (preferred) or editor field,
+    use it as the name part of the key.
+ 3. Change any substring found in
+    `bibtex-autokey-name-change-strings' to the corresponding new
+    one (see documentation of this variable for further detail).
+ 4. For every of at least first `bibtex-autokey-names' names in
+    the name field, determine the last name. If there are maximal
+    `bibtex-autokey-names' + `bibtex-autokey-names-stretch'
+    names, all names are used.
+ 5. From every last name, take at least
+    `bibtex-autokey-name-length' characters (abort only after a
+    consonant or at a word end).
+ 6. Convert all last names according to the conversion function
+    `bibtex-autokey-name-case-convert'.
+ 7. Build the name part of the key by concatenating all
+    abbreviated last names with the string
+    `bibtex-autokey-name-separator' between any two. If there are
+    more names than are used in the name part, prepend the string
+    contained in `bibtex-autokey-additional-names'.
+ 8. Build the year part of the key by truncating the contents of
+    the year field to the rightmost `bibtex-autokey-year-length'
+    digits (useful values are 2 and 4). If the year field is
+    absent, but the entry has a valid crossref field and the
+    variable `bibtex-autokey-year-use-crossref-entry' is non-nil,
+    use the year field of the crossreferenced entry instead.
+ 9. For the title part of the key change the contents of the
+    title field of the entry according to
+    `bibtex-autokey-titleword-change-strings' to the
+    corresponding new one (see documentation of this variable for
+    further detail).
+10. Abbreviate the result to the string up to (but not including)
+    the first occurrence of a regexp matched by the items of
+    `bibtex-autokey-title-terminators' and delete those words which
+    appear in `bibtex-autokey-titleword-ignore'.
+    Build the title part of the key by using at least the first
+    `bibtex-autokey-titlewords' words from this
+    abbreviated title. If the abbreviated title ends after
+    maximal `bibtex-autokey-titlewords' +
+    `bibtex-autokey-titlewords-stretch' words, all
+    words from the abbreviated title are used.
+11. Convert all used titlewords according to the conversion function
+    `bibtex-autokey-titleword-case-convert'.
+12. For every used title word that appears in
+    `bibtex-autokey-titleword-abbrevs' use the corresponding
+    abbreviation (see documentation of this variable for further
+    detail).
+13. From every title word not generated by an abbreviation, take
+    at least `bibtex-autokey-titleword-length' characters (abort
+    only after a consonant or at a word end).
+14. Build the title part of the key by concatenating all
+    abbreviated title words with the string
+    `bibtex-autokey-titleword-separator' between any two.
+15. At least, to get the key, concatenate
+    `bibtex-autokey-prefix-string', the name part, the year part
+    and the title part with `bibtex-autokey-name-year-separator'
+    between the name part and the year part if both are non-empty
+    and `bibtex-autokey-year-title-separator' between the year
+    part and the title part if both are non-empty. If the year
+    part is empty, but not the other two parts,
+    `bibtex-autokey-year-title-separator' is used as well.
+16. If the value of `bibtex-autokey-before-presentation-function'
+    is non-nil, it must be a function taking one argument. This
+    function is then called with the generated key as the
+    argument. The return value of this function (a string) is
+    used as the key.
+17. If the value of `bibtex-autokey-edit-before-use' is non-nil,
+    the key is then presented in the minibuffer to the user,
+    where it can be edited.  The key given by the user is then
+    used."
+  (let* ((pnt (point))
+         (min (bibtex-beginning-of-entry))
+         (max (bibtex-end-of-entry))
+         (namefield (bibtex-autokey-get-namefield min max))
+         (name-etal "")
+         (namelist
+          (let ((nl (bibtex-autokey-get-namelist namefield)))
+            (if (or (not (numberp bibtex-autokey-names))
+                    (<= (length nl)
+                        (+ bibtex-autokey-names
+                           bibtex-autokey-names-stretch)))
+                nl
+              (setq name-etal bibtex-autokey-additional-names)
+              (let (nnl)
+                (while (< (length nnl) bibtex-autokey-names)
+                  (setq nnl (append nnl (list (car nl)))
+                        nl (cdr nl)))
+                nnl))))
+         (namepart
+          (concat
+           (mapconcat (lambda (name) name)
+                      namelist
+                      bibtex-autokey-name-separator)
+           name-etal))
+         (yearfield (bibtex-autokey-get-yearfield min max))
+         (yearpart
+          (if (equal yearfield "")
+              ""
+            (substring
+             yearfield
+             (- (length yearfield) bibtex-autokey-year-length))))
+         (titlestring (bibtex-autokey-get-titlestring min max))
+         (titlelist (bibtex-autokey-get-titlelist titlestring))
+         (titlepart
+          (mapconcat
+           (lambda (name) name)
+           titlelist
+           bibtex-autokey-titleword-separator))
+         (autokey
+          (concat
+           bibtex-autokey-prefix-string
+           namepart
+           (if (not
+                (or
+                 (equal namepart "")
+                 (equal yearpart "")))
+               bibtex-autokey-name-year-separator)
+           yearpart
+           (if (not
+                (or
+                 (and
+                  (equal namepart "")
+                  (equal yearpart ""))
+                 (equal titlepart "")))
+               bibtex-autokey-year-title-separator)
+           titlepart)))
+    (if bibtex-autokey-before-presentation-function
+        (setq
+         autokey
+         (funcall bibtex-autokey-before-presentation-function autokey)))
+    (goto-char pnt)
+    autokey))
+
+(defun bibtex-parse-keys (add verbose &optional abortable)
+  ;; Sets bibtex-reference-keys to the keys used in the whole (possibly
+  ;; restricted) buffer (either as entry keys or as crossref entries).
+  ;; If ADD is non-nil adds the new keys to bibtex-reference-keys instead of
+  ;; simply resetting it. If VERBOSE is non-nil gives messages about
+  ;; progress. If ABORTABLE is non-nil abort on user input.
+  (if bibtex-maintain-sorted-entries
+      (let* ((case-fold-search t)
+            (reference-keys (if add bibtex-reference-keys)))
+        (save-excursion
+          (goto-char (point-min))
+          (if verbose
+              (bibtex-progress-message
+               (concat (buffer-name) ": parsing reference keys")))
+          (if (catch 'userkey
+                (bibtex-skip-to-valid-entry)
+                (while (not (eobp))
+                  (if (and
+                       abortable
+                       (input-pending-p))
+                      (throw 'userkey t))
+                  (if verbose
+                      (bibtex-progress-message))
+                  (let (reference-key
+                        xrefd-reference-key)
+                    (cond
+                     ((looking-at bibtex-entry-head)
+                      (setq
+                       reference-key
+                       (buffer-substring-no-properties
+                        (match-beginning bibtex-key-in-head)
+                        (match-end bibtex-key-in-head)))
+                      (let ((p (point))
+                            (m (bibtex-end-of-entry)))
+                        (goto-char p)
+                       (let ((bounds (bibtex-search-forward-field "crossref" m)))
+                         (if bounds
+                             (setq
+                              xrefd-reference-key
+                              (buffer-substring-no-properties
+                               (1+ (bibtex-start-of-text-in-field bounds))
+                               (1- (bibtex-end-of-text-in-field bounds))))))))
+                     ((bibtex-parse-string)
+                     (let ((bounds (bibtex-parse-string)))
+                       (setq
+                        reference-key
+                        (buffer-substring-no-properties
+                         (bibtex-start-of-reference-key-in-string bounds)
+                         (bibtex-end-of-reference-key-in-string bounds))))))
+                    (forward-char)
+                    (bibtex-skip-to-valid-entry)
+                    (if (not (assoc reference-key reference-keys))
+                        (setq reference-keys
+                              (cons (list reference-key) reference-keys)))
+                    (if (and xrefd-reference-key
+                             (not (assoc xrefd-reference-key reference-keys)))
+                        (setq reference-keys
+                              (cons (list xrefd-reference-key) reference-keys))))))
+              ;; user has aborted by typing a key --> return nil
+              nil
+            ;; successful operation --> return t
+            (setq
+             bibtex-buffer-last-parsed-tick (buffer-modified-tick)
+             bibtex-reference-keys reference-keys)
+            (if verbose
+                (bibtex-progress-message 'done))
+            t)))))
+
+(defun bibtex-parse-buffers-stealthily ()
+  ;; Called by bibtex-run-with-idle-timer. Whenever emacs has been idle
+  ;; for bibtex-parse-keys-timeout seconds, all BibTeX buffers (starting
+  ;; with the current) are parsed.
+  (let ((buffers (buffer-list)))
+    (save-excursion
+      (while (and buffers (not (input-pending-p)))
+        (set-buffer (car buffers))
+        (save-restriction
+          (widen)
+          (if (and
+               (eq major-mode 'bibtex-mode)
+               bibtex-maintain-sorted-entries
+               (not
+                (eq (buffer-modified-tick)
+                    bibtex-buffer-last-parsed-tick)))
+              (if (bibtex-parse-keys nil t t)
+                  ;; successful operation --> remove buffer from list
+                  (setq buffers (cdr buffers)))
+            ;; buffer is no BibTeX buffer or needs no parsing
+            (setq buffers (cdr buffers))))))))
+
+(defun bibtex-complete (string-list &optional complete-strings)
+  ;; Complete word fragment before point to longest prefix of one
+  ;; string defined in STRING-LIST. If point is not after the part of
+  ;; a word, all strings are listed. If COMPLETE-STRINGS is non-nil,
+  ;; add the strings defined in this buffer before cursor to
+  ;; STRING-LIST and remove surrounding delimiters if complete string
+  ;; could be expanded.
+  (let* ((case-fold-search t)
+         (end (point))
+         (beg (save-excursion
+                (re-search-backward "[ \t{\"]")
+                (forward-char)
+                (point)))
+         (part-of-word (buffer-substring-no-properties beg end))
+         (completions (copy-sequence string-list))
+         (completion (save-excursion
+                       (if complete-strings
+                           (while (bibtex-search-backward-string)
+                            (let ((bounds (bibtex-search-backward-string)))
+                              (setq completions
+                                    (cons
+                                     (list
+                                      (buffer-substring-no-properties
+                                       (bibtex-start-of-reference-key-in-string bounds)
+                                       (bibtex-end-of-reference-key-in-string bounds)))
+                                     completions)))))
+                       (setq completions
+                             (sort completions
+                                   (lambda(x y)
+                                     (string-lessp
+                                      (car x)
+                                      (car y)))))
+                       (try-completion part-of-word completions))))
+    (cond ((eq completion t)
+           (if complete-strings
+               ;; remove double-quotes or braces if field is no concatenation
+               (save-excursion
+                 (bibtex-inside-field)
+                 (let* ((bounds (bibtex-enclosing-field)))
+                  (goto-char (bibtex-start-of-text-in-field bounds))
+                  (let ((boundaries (bibtex-parse-field-string)))
+                    (if (and boundaries (equal (cdr boundaries) (bibtex-end-of-text-in-field bounds)))
+                        (bibtex-remove-delimiters)))))))
+          ((not completion)
+           (error "Can't find completion for \"%s\"" part-of-word))
+          ((not (string= part-of-word completion))
+           (delete-region beg end)
+           (insert completion)
+           (if (and (assoc completion completions)
+                    complete-strings)
+               ;; remove double-quotes or braces if field is no concatenation
+               (save-excursion
+                 (bibtex-inside-field)
+                (let* ((bounds (bibtex-enclosing-field)))
+                  (goto-char (bibtex-start-of-text-in-field bounds))
+                  (let ((boundaries (bibtex-parse-field-string)))
+                    (if (and boundaries (equal (cdr boundaries) (bibtex-end-of-text-in-field bounds)))
+                        (bibtex-remove-delimiters)))))))
+          (t
+           (message "Making completion list...")
+           (let ((list (all-completions part-of-word completions)))
+             (with-output-to-temp-buffer "*Completions*"
+               (display-completion-list list)))
+           (message "Making completion list...done")))))
+
+(defun bibtex-do-auto-fill ()
+  (let ((fill-prefix
+         (make-string
+          (+ bibtex-entry-offset bibtex-contline-indentation) ? )))
+    (do-auto-fill)))
+
+(defun bibtex-pop (arg direction)
+  ;; generic function to be used by bibtex-pop-previous and bibtex-pop-next
+  (let (bibtex-help-message)
+    (bibtex-find-text nil))
+  (save-excursion
+    ;; parse current field
+    (bibtex-inside-field)
+    (let* ((case-fold-search t)
+          (bounds (bibtex-enclosing-field))
+          (start-old-text (bibtex-start-of-text-in-field bounds))
+          (stop-old-text (bibtex-end-of-text-in-field bounds))
+          (start-name (bibtex-start-of-name-in-field bounds))
+          (stop-name (bibtex-end-of-name-in-field bounds))
+          (new-text))
+      (goto-char start-name)
+      ;; construct regexp for field with same name as this one,
+      ;; ignoring possible OPT's or ALT's
+      (let* ((field-name
+             (buffer-substring-no-properties
+              (if (looking-at "\\(OPT\\)\\|\\(ALT\\)")
+                  (match-end 0)
+                (point))
+              stop-name)))
+       ;; if executed several times in a row, start each search where
+        ;; the last one was finished
+       (cond ((eq last-command 'bibtex-pop) t)
+             (t
+              (bibtex-enclosing-entry-maybe-empty-head)
+              (setq
+                bibtex-pop-previous-search-point (match-beginning 0)
+                bibtex-pop-next-search-point (point))))
+       (if (eq direction 'previous)
+            (goto-char bibtex-pop-previous-search-point)
+          (goto-char bibtex-pop-next-search-point))
+        ;; Now search for arg'th previous/next similar field
+       (let ((bounds nil)
+             (failure nil))
+         (while (and (not failure) (> arg 0))
+           (cond ((eq direction 'previous)
+                  (setq bounds (bibtex-search-backward-field field-name (point-min)))
+                  (if bounds
+                      (goto-char (bibtex-start-of-field bounds))
+                    (setq failure t)))
+                 ((eq direction 'next)
+                  (setq bounds (bibtex-search-forward-field field-name (point-max)))
+                  (if bounds
+                      (goto-char (bibtex-end-of-field bounds))
+                    (setq failure t))))
+           (setq arg (- arg 1)))
+         (if failure
+             (error (if (eq direction 'previous)
+                        "No previous matching BibTeX field."
+                      "No next matching BibTeX field."))
+           ;; Found a matching field. Remember boundaries.
+           (setq bibtex-pop-previous-search-point (bibtex-start-of-field bounds))
+           (setq bibtex-pop-next-search-point (bibtex-end-of-field bounds))
+           (setq new-text
+                 (buffer-substring-no-properties
+                  (bibtex-start-of-text-in-field bounds)
+                  (bibtex-end-of-text-in-field bounds)))
+           (bibtex-flash-head)
+           ;; Go back to where we started, delete old text, and pop new.
+           (goto-char stop-old-text)
+           (delete-region start-old-text stop-old-text)
+           (insert new-text))))))
+  (let (bibtex-help-message)
+    (bibtex-find-text nil))
+  (setq this-command 'bibtex-pop))
+
+\f
+;; Interactive Functions:
+
+;;;###autoload
+(defun bibtex-mode ()
+  "Major mode for editing BibTeX files.
+
+To submit a problem report, enter \\[bibtex-submit-bug-report] from a
+BibTeX mode buffer.  This automatically sets up a mail buffer with
+version information already added.  You just need to add a description
+of the problem, including a reproducible test case and send the
+message.
+
+
+General information on working with BibTeX mode:
+
+You should use commands as \\[bibtex-Book] to get a template for a
+specific entry. You should then fill in all desired fields using
+\\[bibtex-next-field] to jump from field to field. After having filled
+in all desired fields in the entry, you should clean the new entry
+with command \\[bibtex-clean-entry].
+
+Some features of BibTeX mode are available only by setting variable
+bibtex-maintain-sorted-entries to t. However, then BibTeX mode will
+work with buffer containing only valid (syntactical correct) entries
+and with entries being sorted. This is usually the case, if you have
+created a buffer completely with BibTeX mode and finished every new
+entry with \\[bibtex-clean-entry].
+
+For third party BibTeX buffers, please call the function
+`bibtex-convert-alien' to fully take advantage of all features of
+BibTeX mode.
+
+
+Special information:
+
+A command such as \\[bibtex-Book] will outline the fields for a BibTeX book entry.
+
+The optional fields start with the string OPT, and are thus ignored by BibTeX.
+Alternatives from which only one is required start with the string ALT.
+The OPT or ALT string may be removed from a field with \\[bibtex-remove-OPT-or-ALT].
+\\[bibtex-make-field] inserts a new field after the current one.
+\\[bibtex-kill-field] kills the current field entirely.
+\\[bibtex-yank] will yank the last recently killed field after the
+current field.
+\\[bibtex-remove-delimiters] removes the double-quotes or braces around the text of the current field.
+ \\[bibtex-empty-field] replaces the text of the current field with the default \"\" or {}.
+
+The command \\[bibtex-clean-entry] cleans the current entry, i.e. it removes OPT/ALT
+from all non-empty optional or alternative fields, checks that no required
+fields are empty, and does some formatting dependent on the value of
+bibtex-entry-format.
+Note: some functions in BibTeX mode depend on entries being in a special
+format (all fields beginning on separate lines), so it is usually a bad
+idea to remove `realign' from bibtex-entry-format.
+
+Use \\[bibtex-find-text] to position the cursor at the end of the current field.
+Use \\[bibtex-next-field] to move to end of the next field.
+
+The following may be of interest as well:
+
+  Functions:
+    bibtex-entry
+    bibtex-kill-entry
+    bibtex-yank-pop
+    bibtex-pop-previous
+    bibtex-pop-next
+    bibtex-complete-string
+    bibtex-complete-key
+    bibtex-print-help-message
+    bibtex-generate-autokey
+    bibtex-beginning-of-entry
+    bibtex-end-of-entry
+    bibtex-reposition-window
+    bibtex-mark-entry
+    bibtex-ispell-abstract
+    bibtex-ispell-entry
+    bibtex-narrow-to-entry
+    bibtex-sort-buffer
+    bibtex-validate
+    bibtex-count
+    bibtex-fill-entry
+    bibtex-reformat
+    bibtex-convert-alien
+
+  Variables:
+    bibtex-field-delimiters
+    bibtex-include-OPTcrossref
+    bibtex-include-OPTkey
+    bibtex-user-optional-fields
+    bibtex-entry-format
+    bibtex-sort-ignore-string-entries
+    bibtex-maintain-sorted-entries
+    bibtex-entry-field-alist
+    bibtex-predefined-strings
+    bibtex-string-files
+
+---------------------------------------------------------
+Entry to BibTeX mode calls the value of `bibtex-mode-hook' if that value is
+non-nil.
+
+\\{bibtex-mode-map}"
+  (interactive)
+  (kill-all-local-variables)
+  (use-local-map bibtex-mode-map)
+  (setq major-mode 'bibtex-mode)
+  (setq mode-name "BibTeX")
+  (set-syntax-table bibtex-mode-syntax-table)
+  (setq bibtex-strings bibtex-predefined-strings)
+  (mapcar
+   (lambda (filename)
+     ;; collect pathnames
+     (let* ((path (if bibtex-string-file-path
+                      bibtex-string-file-path
+                    "."))
+            (dirs (split-string path ":+"))
+            (filename (if (string-match "\.bib$" filename)
+                          filename
+                        (concat filename ".bib")))
+            fullfilename
+            (item 0)
+            (size (length dirs)))
+       ;; test filenames
+       (while (and
+               (< item size)
+               (not (file-readable-p
+                     (setq fullfilename
+                           (concat (elt dirs item) "/" filename)))))
+         (setq item (1+ item)))
+       (if (< item size)
+           ;; file was found
+           (let* ((case-fold-search t)
+                 (compl nil))
+            (with-temp-buffer
+              (insert-file-contents fullfilename)
+              (goto-char (point-min))
+              (let ((bounds (bibtex-search-forward-string)))
+                (while bounds
+                  (setq compl
+                        (cons (list (buffer-substring-no-properties
+                                     (bibtex-start-of-reference-key-in-string bounds)
+                                     (bibtex-end-of-reference-key-in-string bounds)))
+                              compl))
+                  (goto-char (bibtex-end-of-string bounds))
+                  (setq bounds (bibtex-search-forward-string)))))
+            (setq bibtex-strings (append bibtex-strings (nreverse compl))))
+         (error
+          "File %s not in paths defined by bibtex-string-file-path variable"
+          filename))))
+   bibtex-string-files)
+  (if bibtex-maintain-sorted-entries
+      (bibtex-run-with-idle-timer
+       1 nil
+       (lambda ()
+         (bibtex-parse-keys nil t t))))
+  ;; to get buffer parsed once if everything else (including things
+  ;; installed in bibtex-mode-hook) has done its work
+  (if (not bibtex-parse-idle-timer)
+      (setq bibtex-parse-idle-timer
+            (bibtex-run-with-idle-timer
+             bibtex-parse-keys-timeout t
+             'bibtex-parse-buffers-stealthily)))
+  ;; Install stealthy parse function if not already installed
+  (make-local-variable 'paragraph-start)
+  (setq paragraph-start "[ \f\n\t]*$")
+  (make-local-variable 'comment-start)
+  (setq comment-start bibtex-comment-start)
+  (make-local-variable 'comment-start-skip)
+  (setq comment-start-skip bibtex-comment-start)
+  (make-local-variable 'comment-column)
+  (setq comment-column 0)
+  (make-local-variable 'defun-prompt-regexp)
+  (setq defun-prompt-regexp "^@[a-zA-Z0-9]+")
+  (make-local-variable 'outline-regexp)
+  (setq outline-regexp "@")
+  (make-local-variable 'normal-auto-fill-function)
+  (setq normal-auto-fill-function 'bibtex-do-auto-fill)
+  (make-local-variable 'font-lock-defaults)
+  (setq font-lock-defaults
+       '(bibtex-font-lock-keywords
+         nil t ((?$ . "\"")
+                ;; Mathematical expressions should be fontified as strings
+                (?\" . ".")
+                ;; Quotes are field delimiters and quote-delimited
+                ;; entries should be fontified in the same way as
+                ;; brace-delimited ones
+                )))
+  (make-local-variable 'font-lock-mark-block-function)
+  (setq font-lock-mark-block-function
+       (lambda ()
+         (set-mark (bibtex-end-of-entry))
+         (bibtex-beginning-of-entry)))
+  (setq imenu-generic-expression
+       (list (list nil bibtex-entry-head bibtex-key-in-head)))
+  (setq imenu-case-fold-search t)
+  ;; XEmacs needs easy-menu-add, Emacs does not care
+  (easy-menu-add bibtex-edit-menu)
+  (easy-menu-add bibtex-entry-menu)
+  (run-hooks 'bibtex-mode-hook))
+
+(defun bibtex-submit-bug-report ()
+  "Submit via mail a bug report on bibtex.el."
+  (interactive)
+  (if (y-or-n-p "Do you want to submit a bug report on BibTeX mode? ")
+      (progn
+        (require 'reporter)
+        (let ((reporter-prompt-for-summary-p t))
+          (reporter-submit-bug-report
+           bibtex-maintainer-address
+           "bibtex.el"
+           (list
+            'system-configuration
+            'system-configuration-options
+            'bibtex-mode-hook
+            'bibtex-parse-keys-timeout
+            ;; possible general errors
+            'bibtex-sort-ignore-string-entries
+            'bibtex-maintain-sorted-entries
+            'bibtex-entry-delimiters
+            'bibtex-field-delimiters
+            'bibtex-comma-after-last-field
+            'bibtex-entry-offset
+            'bibtex-field-indentation
+            'bibtex-text-indentation
+            'bibtex-contline-indentation
+            'bibtex-align-at-equal-sign
+            ;; possible sorting and parsing bugs
+            'bibtex-entry-format
+            'bibtex-add-entry-hook
+            'bibtex-clean-entry-hook
+            ;; possible cleaning error
+            'bibtex-user-optional-fields
+            ;; possible format error
+            'bibtex-predefined-month-strings
+            'bibtex-predefined-strings
+            'bibtex-string-files
+            'bibtex-string-file-path
+            ;; possible format error
+            'bibtex-font-lock-keywords
+            ;; possible bugs regarding fontlocking
+            'bibtex-autokey-prefix-string
+            'bibtex-autokey-names
+            'bibtex-autokey-names-stretch
+            'bibtex-autokey-additional-names
+            'bibtex-autokey-transcriptions
+            'bibtex-autokey-name-change-strings
+            'bibtex-autokey-name-case-convert
+            'bibtex-autokey-name-length
+            'bibtex-autokey-name-separator
+            'bibtex-autokey-year-length
+            'bibtex-autokey-year-use-crossref-entry
+            'bibtex-autokey-titlewords
+            'bibtex-autokey-title-terminators
+            'bibtex-autokey-titlewords-stretch
+            'bibtex-autokey-titleword-ignore
+            'bibtex-autokey-titleword-case-convert
+            'bibtex-autokey-titleword-abbrevs
+            'bibtex-autokey-titleword-change-strings
+            'bibtex-autokey-titleword-length
+            'bibtex-autokey-titleword-separator
+            'bibtex-autokey-name-year-separator
+            'bibtex-autokey-year-title-separator
+            'bibtex-autokey-edit-before-use
+            'bibtex-autokey-before-presentation-function
+            ;; possible bugs regarding automatic reference keys
+            'bibtex-entry-field-alist
+            ;; possible format error
+            'bibtex-help-message
+            'bibtex-include-OPTcrossref
+            'bibtex-include-OPTkey
+            'bibtex-field-kill-ring-max
+            'bibtex-entry-kill-ring-max
+            ;; user variables which shouldn't cause any errors
+            )
+           nil nil
+           (concat bibtex-maintainer-salutation "
+
+I want to report a bug on Emacs BibTeX mode.
+
+I've read the `Bugs' section in the `Emacs' info page, so I know how
+to make a clear and unambiguous report. I have started a fresh Emacs
+via `"invocation-name " --no-init-file --no-site-file', thereafter (in
+case I'm reporting on a version of `bibtex.el' which is not part of
+the standard emacs distribution) I loaded the questionable version
+of `bibtex.el' with `M-x load-file', and then, to produce the buggy
+behaviour, I did the following:")))
+        (message nil))))
+
+(defun bibtex-entry (entry-type)
+  "Insert a new BibTeX entry.
+After insertion it calls the functions in `bibtex-add-entry-hook'."
+  (interactive (let* ((completion-ignore-case t)
+                     (e-t (completing-read
+                            "Entry Type: "
+                            bibtex-entry-field-alist
+                            nil t nil 'bibtex-entry-type-history)))
+                (list e-t)))
+  (if (not bibtex-reference-keys)
+      (bibtex-parse-keys nil t))
+  (let* (required
+         optional
+         (key
+          (if bibtex-maintain-sorted-entries
+              (completing-read
+               (format "%s key: " entry-type)
+               bibtex-reference-keys nil nil nil 'bibtex-key-history)))
+         (e (assoc-ignore-case entry-type bibtex-entry-field-alist))
+         (r-n-o (elt e 1))
+         (c-ref (elt e 2)))
+    (if (not e)
+        (error "Bibtex entry type %s not defined" entry-type))
+    (if (and
+         (member entry-type bibtex-include-OPTcrossref)
+         c-ref)
+        (setq required (elt c-ref 0)
+              optional (elt c-ref 1))
+      (setq required (elt r-n-o 0)
+            optional (elt r-n-o 1)))
+    (if bibtex-maintain-sorted-entries
+       (bibtex-find-entry-location key)
+      (bibtex-move-outside-of-entry))
+    (indent-to-column bibtex-entry-offset)
+    (insert "@" entry-type (bibtex-entry-left-delimiter))
+    (if key
+       (insert key))
+    (save-excursion
+      (mapcar 'bibtex-make-field required)
+      (if (member entry-type bibtex-include-OPTcrossref)
+         (bibtex-make-optional-field '("crossref")))
+      (if bibtex-include-OPTkey
+          (if (or
+               (stringp bibtex-include-OPTkey)
+               (fboundp bibtex-include-OPTkey))
+              (bibtex-make-optional-field
+               (list "key" nil bibtex-include-OPTkey))
+            (bibtex-make-optional-field '("key"))))
+      (mapcar 'bibtex-make-optional-field optional)
+      (mapcar 'bibtex-make-optional-field bibtex-user-optional-fields)
+      (if bibtex-comma-after-last-field
+          (insert ","))
+      (insert "\n")
+      (indent-to-column bibtex-entry-offset)
+      (insert (bibtex-entry-right-delimiter) "\n\n"))
+    (bibtex-next-field t)
+    (run-hooks 'bibtex-add-entry-hook)))
+
+(defun bibtex-print-help-message ()
+  "Prints helpful information about current field in current BibTeX entry."
+  (interactive)
+  (let* ((case-fold-search t)
+         (pnt (point))
+         (field-name
+         (let* ((bounds (bibtex-enclosing-field))
+                (mb (bibtex-start-of-name-in-field bounds))
+                (me (bibtex-end-of-name-in-field bounds)))
+           (goto-char mb)
+           (buffer-substring-no-properties
+            (if (looking-at "OPT\\|ALT")
+                (+ 3 mb)
+              mb)
+            me)))
+         (entry-type
+          (progn
+            (re-search-backward
+             bibtex-entry-maybe-empty-head nil t)
+            (buffer-substring-no-properties
+             (1+ (match-beginning bibtex-type-in-head))
+             (match-end bibtex-type-in-head))))
+         (entry-list
+          (assoc-ignore-case entry-type
+                               bibtex-entry-field-alist))
+         (c-r-list (elt entry-list 2))
+         (req-opt-list
+          (if (and
+               (member entry-type bibtex-include-OPTcrossref)
+               c-r-list)
+              c-r-list
+            (elt entry-list 1)))
+         (list-of-entries (append
+                           (elt req-opt-list 0)
+                           (elt req-opt-list 1)
+                           bibtex-user-optional-fields
+                           (if (member
+                                entry-type
+                                bibtex-include-OPTcrossref)
+                               '(("crossref"
+                                  "Reference key of the crossreferenced entry")))
+                           (if bibtex-include-OPTkey
+                               '(("key"
+                                  "Used for reference key creation if author and editor fields are missing"))))))
+    (goto-char pnt)
+    (let ((comment (assoc-ignore-case field-name list-of-entries)))
+      (if comment
+          (message (elt comment 1))
+        (message "NO COMMENT AVAILABLE")))))
+
+(defun bibtex-make-field (e-t &optional called-by-yank)
+  "Makes a field named E-T in current BibTeX entry.
+This function is for interactive and non-interactive purposes.  To call
+it interactively, just give it no arguments and enter the field name
+using the minibuffer."
+  (interactive "*P")
+  (if (not e-t)
+      (setq
+       e-t
+       (let* ((entry-type
+               (save-excursion
+                 (bibtex-enclosing-entry-maybe-empty-head)
+                 (buffer-substring-no-properties
+                  (1+ (match-beginning bibtex-type-in-head))
+                  (match-end bibtex-type-in-head))))
+              (fl
+               (car (cdr (assoc-ignore-case
+                          entry-type bibtex-entry-field-alist))))
+              (field-list
+               (append
+                (elt fl 0) (elt fl 1) bibtex-user-optional-fields
+                (if bibtex-include-OPTcrossref '(("crossref" nil)))
+                (if bibtex-include-OPTkey '(("key" nil)))))
+              (completion-ignore-case t))
+         (completing-read
+          "BibTeX field name: " field-list
+          nil nil nil bibtex-field-history))))
+  (if (not (consp e-t))
+      (setq e-t (list e-t)))
+  (if (equal (length e-t) 1)
+      (setq e-t (append e-t (list ""))))
+  (if (equal (length e-t) 2)
+      (setq e-t (append e-t (list ""))))
+  (let ((name (if (elt e-t 3)
+                  (concat "ALT" (car e-t))
+                (car e-t))))
+    (if (or (interactive-p) called-by-yank)
+        (let (bibtex-help-message)
+          (bibtex-find-text nil t)
+          (if (looking-at "[}\"]")
+              (forward-char))))
+    (insert ",\n")
+    (indent-to-column
+     (+ bibtex-entry-offset bibtex-field-indentation))
+    (insert name " ")
+    (if bibtex-align-at-equal-sign
+        (indent-to-column
+         (+ bibtex-entry-offset (- bibtex-text-indentation 2))))
+    (insert "= ")
+    (if (not bibtex-align-at-equal-sign)
+        (indent-to-column
+         (+ bibtex-entry-offset bibtex-text-indentation)))
+    (insert (if called-by-yank
+                ""
+              (bibtex-field-left-delimiter))
+            (let ((init (elt e-t 2)))
+              (cond
+               ((stringp init)
+                init)
+               ((fboundp init)
+                (funcall init))
+               (t
+                (error "%s is neither a string nor a function" init))))
+            (if called-by-yank
+                ""
+              (bibtex-field-right-delimiter)))
+    (if (interactive-p)
+        (forward-char -1))))
+
+(defun bibtex-beginning-of-entry ()
+  "Move to beginning of BibTeX entry.
+If inside an entry, move to the beginning of it, otherwise move to the
+beginning of the previous entry.
+If called from a program, this function returns the new location of point."
+  (interactive)
+  (skip-chars-forward " \t")
+  (if (looking-at "@")
+      (forward-char))
+  (re-search-backward "^[ \t]*@" nil 'move))
+
+(defun bibtex-end-of-entry ()
+  "Move to end of BibTeX entry.
+If inside an entry, move to the end of it, otherwise move to the end
+of the previous entry.
+If called from a program, this function returns the new location of point."
+  (interactive)
+  (let* ((case-fold-search t)
+        (valid-entry-head
+         (concat "[ \t]*@[ \t]*\\("
+                 (mapconcat
+                  (lambda (type)
+                    (concat "\\(" (car type) "\\)"))
+                  bibtex-entry-field-alist
+                  "\\|")
+                 "\\)"))
+        (org (point))
+        (pnt (bibtex-beginning-of-entry))
+        err)
+    (cond
+     ((bibtex-parse-string)
+      (let ((bounds (bibtex-parse-string)))
+       (goto-char (bibtex-end-of-string bounds))))
+     ((looking-at "[ \t]*@[ \t]*preamble[ \t\n]*")
+      (goto-char (match-end 0))
+      (cond
+       ((looking-at "(")
+        (if (not (re-search-forward ")[ \t]*\n\n" nil 'move))
+            (setq err t)))
+       ((looking-at "{")
+        (if (not (re-search-forward "}[ \t]*\n\n" nil 'move))
+            (setq err t)))
+       (t
+        (setq err t)))
+      (if (not err)
+          (progn
+            (goto-char (match-beginning 0))
+            (forward-char))))
+     ((looking-at valid-entry-head)
+      (bibtex-search-entry t nil t)
+      (if (not (equal (match-beginning 0) pnt))
+          (setq err t)))
+     (t
+      (if (interactive-p)
+          (message "Not on a known BibTeX entry."))
+      (goto-char org)))
+    (if err
+        (progn
+          (goto-char pnt)
+          (error "Syntactical incorrect entry starts here"))))
+  (point))
+
+(defun bibtex-reposition-window (arg)
+  "Make the current BibTeX entry visible."
+  (interactive "P")
+  (save-excursion
+    (goto-char
+     (/ (+ (bibtex-beginning-of-entry) (bibtex-end-of-entry)) 2))
+    (recenter arg)))
+
+(defun bibtex-mark-entry ()
+  "Put mark at beginning, point at end of current BibTeX entry."
+  (interactive)
+  (set-mark (bibtex-beginning-of-entry))
+  (bibtex-end-of-entry))
+
+(defun bibtex-count-entries (&optional count-string-entries)
+  "Count number of entries in current buffer or region.
+With prefix argument COUNT-STRING-ENTRIES it counts all entries,
+otherwise it counts all except Strings.
+If mark is active it counts entries in region, if not in whole buffer."
+  (interactive "P")
+  (let ((pnt (point))
+        (start-point
+         (if (bibtex-mark-active)
+             (region-beginning)
+           (bibtex-beginning-of-first-entry)))
+        (end-point
+         (if (bibtex-mark-active)
+             (region-end)
+           (point-max)))
+        (number 0)
+        (bibtex-sort-ignore-string-entries
+         (not count-string-entries)))
+    (save-restriction
+      (narrow-to-region start-point end-point)
+      (goto-char start-point)
+      (bibtex-map-entries
+       (lambda (current)
+         (setq number (1+ number)))))
+    (message (concat (if (bibtex-mark-active) "Region" "Buffer")
+                     " contains %d entries.") number)
+    (goto-char pnt)))
+
+(defun bibtex-ispell-entry ()
+  "Spell whole BibTeX entry."
+  (interactive)
+  (ispell-region (bibtex-beginning-of-entry) (bibtex-end-of-entry)))
+
+(defun bibtex-ispell-abstract ()
+  "Spell abstract of BibTeX entry."
+  (interactive)
+  (let* ((case-fold-search t)
+        (pnt (bibtex-end-of-entry)))
+    (bibtex-beginning-of-entry)
+    (let ((bounds (bibtex-search-forward-field "abstract" pnt)))
+      (if bounds
+         (ispell-region (bibtex-start-of-text-in-field bounds) (bibtex-end-of-text-in-field bounds))
+       (error "No abstract in entry")))))
+
+(defun bibtex-narrow-to-entry ()
+  "Narrow buffer to current BibTeX entry."
+  (interactive)
+  (save-excursion
+    (narrow-to-region
+     (bibtex-beginning-of-entry) (bibtex-end-of-entry))))
+
+(defun bibtex-sort-buffer ()
+  "Sort BibTeX buffer alphabetically by key.
+Text outside of BibTeX entries is not affected.  If
+`bibtex-sort-ignore-string-entries' is non-nil, @String entries will be
+ignored."
+  (interactive)
+  (save-restriction
+    (narrow-to-region
+     (bibtex-beginning-of-first-entry)
+     (save-excursion
+       (goto-char (point-max))
+       (bibtex-end-of-entry)))
+    (bibtex-skip-to-valid-entry)
+    (sort-subr
+     nil
+     ;; NEXTREC function
+     'bibtex-skip-to-valid-entry
+     ;; ENDREC function
+     'bibtex-end-of-entry
+     ;; STARTKEY function
+     (lambda ()
+       (let* ((case-fold-search t))
+         (re-search-forward bibtex-entry-head)
+         (buffer-substring-no-properties
+          (match-beginning bibtex-key-in-head)
+          (match-end bibtex-key-in-head)))))))
+
+(defun bibtex-find-entry-location (entry-name &optional ignore-dups)
+  "Looking for place to put the BibTeX entry named ENTRY-NAME.
+Performs a binary search (therefore, buffer is assumed to be in sorted
+order, without duplicates (see \\[bibtex-validate]), if it is
+not, `bibtex-find-entry-location' will fail).  If entry-name is already
+used as a reference key, an error is signaled.  However, if optional
+variable IGNORE-DUPS is non-nil, no error messages about duplicate
+entries are signaled, but the error handling is assumed to be made in
+the calling function.
+The value is nil if a duplicate entry error occurred,
+and t in all other cases."
+  (let* ((case-fold-search t)
+         (left
+          (progn
+            (bibtex-beginning-of-first-entry)
+            (bibtex-skip-to-valid-entry)
+            (bibtex-end-of-entry)))
+         (right
+          (progn
+            (bibtex-beginning-of-last-entry)
+            (bibtex-skip-to-valid-entry t)
+            (point)))
+         actual-point
+         actual-key
+         (done (>= left right))
+         new
+         dup)
+    (while (not done)
+      (setq actual-point (/ (+ left right) 2))
+      (goto-char actual-point)
+      (bibtex-skip-to-valid-entry t)
+      (setq actual-key
+            (progn
+              (re-search-forward bibtex-entry-head)
+              (buffer-substring-no-properties
+               (match-beginning bibtex-key-in-head)
+               (match-end bibtex-key-in-head))))
+      (cond
+       ((string-lessp entry-name actual-key)
+        (setq new (bibtex-beginning-of-entry))
+        (if (equal right new)
+            (setq done t)
+          (setq right new)))
+       ((string-lessp actual-key entry-name)
+        (setq new (bibtex-end-of-entry))
+        (if (equal left new)
+            (setq done t)
+          (setq left new)))
+       ((string-equal actual-key entry-name)
+        (setq dup t
+              done t)
+        (if (not ignore-dups)
+            (progn
+              (bibtex-beginning-of-entry)
+              (error "Entry with key `%s' already exists" entry-name))))))
+    (if dup
+        (progn
+          (bibtex-beginning-of-entry)
+          nil)
+      (goto-char right)
+      (setq actual-key
+            (if (looking-at bibtex-entry-head)
+                (buffer-substring-no-properties
+                 (match-beginning bibtex-key-in-entry)
+                 (match-end bibtex-key-in-entry))))
+      (if (or
+           (not actual-key)
+           (string-lessp actual-key entry-name))
+          ;; buffer contains no valid entries or
+          ;; greater than last entry --> append
+          (progn
+            (bibtex-end-of-entry)
+            (if (not (bobp))
+                (newline (forward-line 2)))
+            (beginning-of-line))
+        (goto-char right))
+      t)))
+
+(defun bibtex-validate (&optional test-thoroughly)
+  "Validate if buffer or region is syntactically correct.
+Only known entry types are checked, so you can put comments
+outside of entries.
+With optional argument TEST-THOROUGHLY non-nil it checks for absence of
+required fields and questionable month fields as well.
+If mark is active, it validates current region, if not whole buffer.
+Returns t if test was successful, nil otherwise."
+  (interactive "P")
+  (let* (error-list
+        syntax-error
+        (case-fold-search t)
+        (valid-bibtex-entry
+         (concat
+          "@[ \t]*\\(\\(string\\)\\|"
+          (mapconcat
+           (lambda (type)
+             (concat "\\(" (car type) "\\)"))
+           bibtex-entry-field-alist
+           "\\|")
+          "\\)"))
+        (pnt (point))
+        (start-point
+         (if (bibtex-mark-active)
+             (region-beginning)
+           (bibtex-beginning-of-first-entry)))
+        (end-point
+         (if (bibtex-mark-active)
+             (region-end)
+           (point-max))))
+    (save-restriction
+      (narrow-to-region start-point end-point)
+      ;; looking if entries fit syntactical structure
+      (goto-char start-point)
+      (bibtex-progress-message "Checking syntactical structure")
+      (while (re-search-forward "^[ \t]*@" nil t)
+        (bibtex-progress-message)
+        (forward-char -1)
+        (let ((p (point))
+              (must-match
+               (looking-at valid-bibtex-entry)))
+          (if (not must-match)
+              (forward-char)
+            (let (bibtex-sort-ignore-string-entries)
+              (bibtex-skip-to-valid-entry))
+            (if (equal (point) p)
+                (forward-char)
+              (goto-char p)
+              (setq
+               error-list
+               (cons (list
+                      (bibtex-current-line)
+                      "Syntax error (check esp. commas, braces, and quotes)")
+                     error-list))
+              (forward-char)))))
+      (bibtex-progress-message 'done)
+      (if error-list
+          (setq syntax-error t)
+        ;; looking for correct sort order and duplicates (only if
+        ;; there were no syntax errors)
+        (if bibtex-maintain-sorted-entries
+            (let (previous)
+              (goto-char start-point)
+              (bibtex-progress-message "Checking correct sort order")
+              (bibtex-map-entries
+               (lambda (current)
+                 (bibtex-progress-message)
+                 (cond ((or (not previous)
+                            (string< previous current))
+                        (setq previous current))
+                       ((string-equal previous current)
+                        (setq
+                         error-list
+                         (cons (list (bibtex-current-line)
+                                     "Duplicate key with previous")
+                               error-list)))
+                       (t
+                        (setq previous current
+                              error-list
+                              (cons (list (bibtex-current-line)
+                                          "Entries out of order")
+                                    error-list))))))
+              (bibtex-progress-message 'done)))
+        (if test-thoroughly
+            (progn
+              (goto-char start-point)
+              (bibtex-progress-message
+               "Checking required fields and month fields")
+              (let ((bibtex-sort-ignore-string-entries t)
+                    (questionable-month
+                     (concat
+                      "[{\"]\\("
+                      (mapconcat
+                       (lambda (mon)
+                         (concat "\\(" (car mon) "\\)"))
+                       bibtex-predefined-month-strings
+                       "\\|")
+                      "\\)[}\"]")))
+                (bibtex-map-entries
+                 (lambda (current)
+                   (bibtex-progress-message)
+                   (let* ((beg (bibtex-beginning-of-entry))
+                          (end (bibtex-end-of-entry))
+                          (entry-list
+                           (progn
+                             (goto-char beg)
+                             (bibtex-search-entry nil end)
+                             (assoc-ignore-case
+                              (buffer-substring-no-properties
+                               (1+ (match-beginning bibtex-type-in-head))
+                               (match-end bibtex-type-in-head))
+                              bibtex-entry-field-alist)))
+                          (req (copy-sequence (elt (elt entry-list 1) 0)))
+                          (creq (copy-sequence (elt (elt entry-list 2) 0)))
+                          crossref-there)
+                     (goto-char beg)
+                    (let ((bounds (bibtex-search-forward-field bibtex-field-name end)))
+                      (while bounds
+                        (let ((field-name
+                               (buffer-substring-no-properties
+                                (bibtex-start-of-name-in-field bounds)
+                                (bibtex-end-of-name-in-field bounds))))
+                          (if (and (equal (downcase field-name) "month")
+                                   (string-match
+                                    questionable-month
+                                    (buffer-substring-no-properties
+                                     (bibtex-start-of-text-in-field bounds)
+                                     (bibtex-end-of-text-in-field bounds))))
+                              (setq
+                               error-list
+                               (cons
+                                (list
+                                 (bibtex-current-line)
+                                 "Questionable month field (delimited string)")
+                                error-list)))
+                          (setq
+                           req
+                           (delete (assoc-ignore-case field-name req) req)
+                           creq
+                           (delete (assoc-ignore-case field-name creq) creq))
+                          (if (equal (downcase field-name) "crossref")
+                              (setq crossref-there t)))
+                        (goto-char (bibtex-end-of-field bounds))
+                        (setq bounds (bibtex-search-forward-field bibtex-field-name end))))
+                     (if crossref-there
+                         (setq req creq))
+                     (if (or (> (length req) 1)
+                             (and (= (length req) 1)
+                                  (not (elt (car req) 3))))
+                         ;; two (or more) fields missed or one field
+                         ;; missed and this isn't flagged alternative
+                         ;; (notice that this fails if there are more
+                         ;; than two alternatives in a BibTeX entry,
+                         ;; which isn't the case momentarily)
+                         (setq
+                          error-list
+                          (cons
+                           (list (save-excursion
+                                   (bibtex-beginning-of-entry)
+                                   (bibtex-current-line))
+                                 (concat
+                                  "Required field \""
+                                  (car (car req))
+                                  "\" missing"))
+                           error-list)))))))
+              (bibtex-progress-message 'done)))))
+    (goto-char pnt)
+    (if error-list
+        (let ((bufnam (buffer-name))
+              (dir default-directory))
+          (setq error-list
+                (sort error-list
+                      (lambda (a b)
+                        (< (car a) (car b)))))
+          (let ((pop-up-windows t))
+            (pop-to-buffer nil t))
+          (switch-to-buffer
+           (get-buffer-create "*BibTeX validation errors*") t)
+          ;; don't use switch-to-buffer-other-window, since this
+          ;; doesn't allow the second parameter NORECORD
+          (setq default-directory dir)
+          (toggle-read-only -1)
+          (compilation-mode)
+          (delete-region (point-min) (point-max))
+          (goto-char (point-min))
+          (insert
+           "BibTeX mode command `bibtex-validate'\n"
+           (if syntax-error
+               "Maybe undetected errors due to syntax errors. Correct and validate again."
+             "")
+           "\n")
+          (while error-list
+            (insert
+             bufnam ":" (number-to-string (elt (car error-list) 0))
+             ": " (elt (car error-list) 1) "\n")
+            (setq error-list (cdr error-list)))
+          (compilation-parse-errors nil nil)
+          (setq compilation-old-error-list compilation-error-list)
+          ;; this is necessary to avoid reparsing of buffer if you
+          ;; switch to compilation buffer and enter
+          ;; `compile-goto-error'
+          (set-buffer-modified-p nil)
+          (toggle-read-only 1)
+          (goto-char (point-min))
+          (other-window -1)
+          ;; return nil
+          nil)
+      (if (bibtex-mark-active)
+          (message "Region is syntactically correct")
+        (message "Buffer is syntactically correct"))
+      t)))
+
+(defun bibtex-next-field (arg)
+  "Finds end of text of next BibTeX field; with ARG, to its beginning."
+  (interactive "P")
+  (bibtex-inside-field)
+  (let ((start (point)))
+    (condition-case ()
+       (let ((bounds (bibtex-enclosing-field)))
+         (goto-char (bibtex-end-of-field bounds))
+         (forward-char 2))
+      (error
+       (goto-char start)
+       (end-of-line)
+       (forward-char))))
+  (bibtex-find-text arg t))
+
+(defun bibtex-find-text (arg &optional as-if-interactive silent)
+  "Go to end of text of current field; with ARG, go to beginning."
+  (interactive "P")
+  (bibtex-inside-field)
+  (let ((bounds (bibtex-enclosing-field (or (interactive-p) as-if-interactive))))
+    (if bounds
+       (progn
+         (if arg
+             (progn
+               (goto-char (bibtex-start-of-text-in-field bounds))
+               (if (looking-at "[{\"]")
+                   (forward-char)))
+           (goto-char (bibtex-end-of-text-in-field bounds))
+           (if (or
+                (= (preceding-char) ?})
+                (= (preceding-char) ?\"))
+               (forward-char -1)))
+         (if bibtex-help-message
+             (bibtex-print-help-message)))
+      (beginning-of-line)
+      (cond
+       ((bibtex-parse-string)
+       (let ((bounds (bibtex-parse-string)))
+         (goto-char
+          (if arg
+              (bibtex-start-of-text-in-string bounds)
+            (bibtex-end-of-text-in-string bounds)))))
+       ((looking-at bibtex-entry-maybe-empty-head)
+       (goto-char
+        (if arg
+            (match-beginning bibtex-key-in-head)
+          (match-end 0))))
+       (t
+       (if (not silent)
+           (error "Not on BibTeX field")))))))
+
+(defun bibtex-remove-OPT-or-ALT ()
+  "Removes the string starting optional/alternative fields.
+Aligns text and goes thereafter to end of text."
+  (interactive)
+  (bibtex-inside-field)
+  (let* ((case-fold-search t)
+        (bounds (bibtex-enclosing-field)))
+    (save-excursion
+      (goto-char (bibtex-start-of-name-in-field bounds))
+      (if (looking-at "OPT\\|ALT")
+          (progn
+            (delete-char (length "OPT"))
+            ;; make field non-OPT
+            (search-forward "=")
+            (forward-char -1)
+            (delete-horizontal-space)
+            (if bibtex-align-at-equal-sign
+                (indent-to-column (- bibtex-text-indentation 2))
+              (insert " "))
+            (search-forward "=")
+            (delete-horizontal-space)
+            (if bibtex-align-at-equal-sign
+                (insert " ")
+              (indent-to-column bibtex-text-indentation)))))
+    (bibtex-inside-field)))
+
+(defun bibtex-remove-delimiters ()
+  "Removes \"\" or {} around string."
+  (interactive)
+  (save-excursion
+    (bibtex-inside-field)
+    (let* ((case-fold-search t)
+          (bounds (bibtex-enclosing-field))
+          (stop (copy-marker (bibtex-end-of-text-in-field bounds))))
+      (goto-char (bibtex-start-of-text-in-field bounds))
+      (let* ((boundaries (bibtex-search-forward-field-string stop)))
+       (while boundaries
+         (let ((text-end (copy-marker (cdr boundaries))))
+           (goto-char (car boundaries))
+           (delete-char 1)
+           (goto-char text-end)
+           (delete-backward-char 1)
+           (setq boundaries (bibtex-search-forward-field-string stop))))))))
+
+(defun bibtex-kill-field (&optional copy-only)
+  "Kills the entire enclosing BibTeX field.
+With prefix arg COPY-ONLY, copy the current field to `bibtex-field-kill-ring,'
+but do not actually kill it."
+  (interactive "P")
+  (let* ((pnt (point))
+        (case-fold-search t))
+    (bibtex-inside-field)
+    (let* ((bounds (bibtex-enclosing-field))
+          (the-end (bibtex-end-of-field bounds))
+          (the-beginning (bibtex-start-of-field bounds)))
+      (goto-char the-end)
+      (skip-chars-forward " \t\n,")
+      (setq
+       bibtex-field-kill-ring
+       (cons
+        (list
+         'field
+         (buffer-substring-no-properties
+          (bibtex-start-of-name-in-field bounds)
+          (bibtex-end-of-name-in-field bounds))
+         (buffer-substring-no-properties
+          (bibtex-start-of-text-in-field bounds)
+          (bibtex-end-of-text-in-field bounds)))
+        bibtex-field-kill-ring))
+      (if (> (length bibtex-field-kill-ring) bibtex-field-kill-ring-max)
+          (setcdr
+           (nthcdr (1- bibtex-field-kill-ring-max) bibtex-field-kill-ring)
+           nil))
+      (setq bibtex-field-kill-ring-yank-pointer bibtex-field-kill-ring)
+      (if copy-only
+          (goto-char pnt)
+        (delete-region the-beginning the-end)
+        (let (bibtex-help-message)
+          (bibtex-find-text nil t t)))))
+  (setq bibtex-last-kill-command 'field))
+
+(defun bibtex-copy-field-as-kill ()
+  (interactive)
+  (bibtex-kill-field t))
+
+(defun bibtex-kill-entry (&optional copy-only)
+  "Kill the entire enclosing BibTeX entry.
+With prefix arg COPY-ONLY the current entry to
+`bibtex-entry-kill-ring', but do not actually kill it."
+  (interactive "P")
+  (let* ((pnt (point))
+        (case-fold-search t)
+        (beg (bibtex-beginning-of-entry))
+        (end
+         (progn
+           (bibtex-end-of-entry)
+           (if (re-search-forward
+                bibtex-entry-maybe-empty-head nil 'move)
+               (goto-char (match-beginning 0)))
+           (point))))
+    (setq
+     bibtex-entry-kill-ring
+     (cons
+      (list 'entry (buffer-substring-no-properties beg end))
+      bibtex-entry-kill-ring))
+    (if (> (length bibtex-entry-kill-ring) bibtex-entry-kill-ring-max)
+        (setcdr
+         (nthcdr (1- bibtex-entry-kill-ring-max) bibtex-entry-kill-ring)
+         nil))
+    (setq bibtex-entry-kill-ring-yank-pointer bibtex-entry-kill-ring)
+    (if copy-only
+        (goto-char pnt)
+      (delete-region beg end)))
+  (setq bibtex-last-kill-command 'entry))
+
+(defun bibtex-copy-entry-as-kill ()
+  (interactive)
+  (bibtex-kill-entry t))
+
+(defun bibtex-yank (&optional n)
+  "Reinsert the last BibTeX item.
+More precisely, reinsert the field or entry killed or yanked most recently.
+With argument N, reinsert the Nth most recently killed BibTeX item.
+See also the command \\[bibtex-yank-pop]]."
+  (interactive "*p")
+  (bibtex-insert-current-kill (1- n))
+  (setq this-command 'bibtex-yank))
+
+(defun bibtex-yank-pop (n)
+  "Replace just-yanked killed BibTeX item with a different.
+This command is allowed only immediately after a `bibtex-yank' or a
+`bibtex-yank-pop'.
+At such a time, the region contains a reinserted previously killed
+BibTeX item.  `bibtex-yank-pop' deletes that item and inserts in its
+place a different killed BibTeX item.
+
+With no argument, the previous kill is inserted.
+With argument N, insert the Nth previous kill.
+If N is negative, this is a more recent kill.
+
+The sequence of kills wraps around, so that after the oldest one
+comes the newest one."
+  (interactive "*p")
+  (if (not (eq last-command 'bibtex-yank))
+      (error "Previous command was not a BibTeX yank"))
+  (setq this-command 'bibtex-yank)
+  (let ((inhibit-read-only t))
+    (delete-region (point) (mark t))
+    (bibtex-insert-current-kill n)))
+
+(defun bibtex-empty-field ()
+  "Delete the text part of the current field, replace with empty text."
+  (interactive)
+  (bibtex-inside-field)
+  (let ((bounds (bibtex-enclosing-field)))
+    (goto-char (bibtex-start-of-text-in-field bounds))
+    (delete-region (point) (bibtex-end-of-text-in-field bounds))
+    (insert (concat (bibtex-field-left-delimiter)
+                   (bibtex-field-right-delimiter)) )
+    (bibtex-find-text t)))
+
+(defun bibtex-pop-previous (arg)
+  "Replace text of current field with the similar field in previous entry.
+With arg, goes up ARG entries.  Repeated, goes up so many times.  May be
+intermixed with \\[bibtex-pop-next] (bibtex-pop-next)."
+  (interactive "p")
+  (bibtex-pop arg 'previous))
+
+(defun bibtex-pop-next (arg)
+  "Replace text of current field with the text of similar field in next entry.
+With arg, goes down ARG entries.  Repeated, goes down so many times.  May be
+intermixed with \\[bibtex-pop-previous] (bibtex-pop-previous)."
+  (interactive "p")
+  (bibtex-pop arg 'next))
+
+(defun bibtex-clean-entry (&optional new-reference-key called-by-reformat)
+  "Finish editing the current BibTeX entry and clean it up.
+Checks that no required fields are empty and formats entry dependent
+on the value of bibtex-entry-format.
+If the reference key of the entry is empty or a prefix argument is given,
+calculate a new reference key (note: this only will work if fields in entry
+begin on separate lines prior to calling bibtex-clean-entry or if 'realign is
+contained in bibtex-entry-format).
+Don't call this on `string' or `preamble' entries.
+At end of the cleaning process, the functions in
+bibtex-clean-entry-hook are called with region narrowed to entry."
+  (interactive "P")
+  (bibtex-format-entry)
+  (let* ((case-fold-search t)
+         (eob (bibtex-end-of-entry))
+         (key (progn
+                (bibtex-beginning-of-entry)
+                (if (re-search-forward
+                     bibtex-entry-head eob t)
+                    (buffer-substring-no-properties
+                     (match-beginning bibtex-key-in-head)
+                     (match-end bibtex-key-in-head))))))
+    (if (or
+         new-reference-key
+         (not key))
+        (progn
+          (let ((autokey
+                 (if bibtex-autokey-edit-before-use
+                     (read-from-minibuffer
+                      "Key to use: " (bibtex-generate-autokey) nil nil
+                      'bibtex-key-history)
+                   (bibtex-generate-autokey))))
+            (bibtex-beginning-of-entry)
+            (re-search-forward bibtex-entry-maybe-empty-head)
+            (if (match-beginning bibtex-key-in-head)
+                (delete-region (match-beginning bibtex-key-in-head)
+                               (match-end bibtex-key-in-head)))
+            (insert autokey)
+            (let* ((start (bibtex-beginning-of-entry))
+                   (end (progn
+                          (bibtex-end-of-entry)
+                          (if (re-search-forward
+                               bibtex-entry-maybe-empty-head nil 'move)
+                              (goto-char (match-beginning 0)))
+                          (point)))
+                   (entry (buffer-substring start end)))
+              (delete-region start end)
+              (let ((success
+                     (or
+                      called-by-reformat
+                      (not bibtex-maintain-sorted-entries)
+                      (bibtex-find-entry-location autokey t))))
+                (insert entry)
+                (forward-char -1)
+                (bibtex-beginning-of-entry)
+                (re-search-forward bibtex-entry-head)
+                (if (not success)
+                    (error
+                     "New inserted entry yields duplicate key"))))))))
+  (if (not called-by-reformat)
+      (save-excursion
+        (save-restriction
+          (narrow-to-region
+           (bibtex-beginning-of-entry) (bibtex-end-of-entry))
+          (bibtex-parse-keys t nil)
+          (run-hooks 'bibtex-clean-entry-hook)))))
+
+(defun bibtex-fill-entry ()
+  "Fill current entry.
+Realigns entry, so that every field starts on a separate line.  Field
+names appear in column `bibtex-field-indentation', field text starts in
+column `bibtex-text-indentation' and continuation lines start here, too.
+If `bibtex-align-at-equal-sign' is non-nil, align equal signs also."
+  (interactive "*")
+  (let ((pnt (copy-marker (point)))
+        (end (copy-marker (bibtex-end-of-entry))))
+    (bibtex-beginning-of-entry)
+    (bibtex-delete-whitespace)
+    (indent-to-column bibtex-entry-offset)
+    (let ((bounds (bibtex-search-forward-field bibtex-field-name end)))
+      (while bounds
+       (let* ((begin-field (copy-marker (bibtex-start-of-field bounds)))
+              (end-field (copy-marker (bibtex-end-of-field bounds)))
+              (begin-name (copy-marker (bibtex-start-of-name-in-field bounds)))
+              (end-name (copy-marker (bibtex-end-of-name-in-field bounds))))
+         (goto-char begin-field)
+         (forward-char)
+         (bibtex-delete-whitespace)
+         (open-line 1)
+         (forward-char)
+         (indent-to-column
+          (+ bibtex-entry-offset bibtex-field-indentation))
+         (re-search-forward "[ \t\n]*=" end)
+         (replace-match "=")
+         (forward-char -1)
+         (if bibtex-align-at-equal-sign
+             (indent-to-column
+              (+ bibtex-entry-offset (- bibtex-text-indentation 2)))
+           (insert " "))
+         (forward-char)
+         (bibtex-delete-whitespace)
+         (if bibtex-align-at-equal-sign
+             (insert " ")
+           (indent-to-column bibtex-text-indentation))
+         (while (re-search-forward "[ \t\n]+" end-field 'move)
+           (replace-match " "))
+         (bibtex-do-auto-fill)
+         (goto-char end-field))
+       (setq bounds (bibtex-search-forward-field bibtex-field-name end))))
+    (if (looking-at ",")
+        (forward-char))
+    (bibtex-delete-whitespace)
+    (open-line 1)
+    (forward-char)
+    (indent-to-column bibtex-entry-offset)
+    (goto-char pnt)))
+
+(defun bibtex-reformat (&optional additional-options called-by-convert-alien)
+  "Reformat all BibTeX entries in buffer or region.
+With prefix argument, read options for reformatting from minibuffer.
+With \\[universal-argument] \\[universal-argument] prefix argument, reuse previous answers (if any) again.
+If mark is active it reformats entries in region, if not in whole buffer."
+  (interactive "*P")
+  (let* ((pnt (point))
+         (use-previous-options
+          (and (equal (prefix-numeric-value additional-options) 16)
+               (or bibtex-reformat-previous-options
+                   bibtex-reformat-previous-reference-keys)))
+         (bibtex-entry-format
+          (if additional-options
+              (if use-previous-options
+                  bibtex-reformat-previous-options
+                (setq
+                 bibtex-reformat-previous-options
+                 (delq
+                  nil
+                  (list
+                   (if (or
+                        called-by-convert-alien
+                        (y-or-n-p
+                         "Realign entries (recommended for files not created by BibTeX mode)? "))
+                       'realign)
+                   (if (y-or-n-p
+                        "Remove empty optional and alternative fields? ")
+                       'opts-or-alts)
+                   (if (y-or-n-p
+                        "Remove delimiters around pure numerical fields? ")
+                       'numerical-fields)
+                   (if (y-or-n-p (concat
+                                  (if bibtex-comma-after-last-field
+                                      "Insert"
+                                    "Remove")
+                                  " comma at end of entry? "))
+                       'last-comma)
+                   (if (y-or-n-p
+                        "Replace double page dashes by single ones? ")
+                       'page-dashes)
+                   (if (y-or-n-p
+                        "Force delimiters? ")
+                       'delimiters)
+                   (if (y-or-n-p
+                        "Unify case of entry types and field names? ")
+                       'unify-case)))))
+            '(realign)))
+         (reformat-reference-keys
+             (if additional-options
+                 (if use-previous-options
+                     bibtex-reformat-previous-reference-keys
+                   (setq
+                    bibtex-reformat-previous-reference-keys
+                    (y-or-n-p "Generate new reference keys automatically? ")))))
+         bibtex-autokey-edit-before-use
+         (bibtex-sort-ignore-string-entries t)
+         (start-point
+          (if (bibtex-mark-active)
+              (region-beginning)
+            (progn
+              (bibtex-beginning-of-first-entry)
+              (bibtex-skip-to-valid-entry)
+              (point))))
+         (end-point
+          (if (bibtex-mark-active)
+              (region-end)
+            (point-max)))
+         (valid-bibtex-entry
+          (concat
+           "[ \t\n]+\\(@[ \t]*\\("
+           (mapconcat
+            (lambda (type)
+              (concat "\\(" (car type) "\\)"))
+            bibtex-entry-field-alist
+            "\\|")
+           "\\)\\)")))
+    (save-restriction
+      (narrow-to-region start-point end-point)
+      (if (memq 'realign bibtex-entry-format)
+          (progn
+            (goto-char (point-min))
+            (while (re-search-forward valid-bibtex-entry nil t)
+              (replace-match "\n\\1"))))
+      (goto-char start-point)
+      (bibtex-progress-message "Formatting" 1)
+      (bibtex-map-entries
+       (lambda (current)
+         (bibtex-progress-message)
+         (bibtex-clean-entry reformat-reference-keys reformat-reference-keys)
+         (if (memq 'realign bibtex-entry-format)
+             (progn
+               (bibtex-end-of-entry)
+               (bibtex-delete-whitespace)
+               (open-line 2)))))
+      (bibtex-progress-message 'done))
+    (if (and
+         reformat-reference-keys
+         bibtex-maintain-sorted-entries
+         (not called-by-convert-alien))
+        (progn
+          (bibtex-sort-buffer)
+          (setq bibtex-reference-keys nil)
+          (bibtex-parse-keys nil t t)))
+    (goto-char pnt)))
+
+(defun bibtex-convert-alien (&optional do-additional-reformatting)
+  "Converts an alien BibTeX buffer to be fully usable by BibTeX mode.
+If a file doesn't confirm with some standards used by BibTeX mode,
+some of the high-level features of BibTeX mode won't be available.
+This function tries to convert current buffer to confirm with these standards.
+With prefix argument DO-ADDITIONAL-REFORMATTING
+non-nil, read options for reformatting entries from minibuffer."
+  (interactive "*P")
+  (message "Starting to validate buffer...")
+  (sit-for 1 nil t)
+  (goto-char (point-min))
+  (while (re-search-forward "[ \t\n]+@" nil t)
+    (replace-match "\n@"))
+  (message
+   "If errors occur, correct them and call `bibtex-convert-alien' again")
+  (sit-for 5 nil t)
+  (if (let ((bibtex-mark-active)
+            bibtex-maintain-sorted-entries)
+        (bibtex-validate))
+      (progn
+        (message "Starting to reformat entries...")
+        (sit-for 2 nil t)
+        (bibtex-reformat do-additional-reformatting t)
+        (if bibtex-maintain-sorted-entries
+            (progn
+              (message "Starting to sort buffer...")
+              (bibtex-sort-buffer)))
+        (goto-char (point-max))
+        (message "Buffer is now parsable. Please save it."))))
+
+(defun bibtex-complete-string ()
+  "Complete word fragment before point to longest prefix of a defined string.
+If point is not after the part of a word, all strings are listed.
+Remove surrounding delimiters if complete string could be expanded."
+  (interactive "*")
+  (bibtex-complete bibtex-strings t))
+
+(defun bibtex-complete-key ()
+  "Complete word fragment before point to longest prefix of a defined key.
+If point is not after the part of a word, all keys are listed.  This
+function is most useful in completing crossref entries."
+  (interactive "*")
+  (if (not bibtex-reference-keys)
+      (bibtex-parse-keys nil t))
+  (bibtex-complete bibtex-reference-keys))
+
+(defun bibtex-Article ()
+  "Insert a new BibTeX @Article entry; see also `bibtex-entry'."
+  (interactive)
+  (bibtex-entry "Article"))
+
+(defun bibtex-Book ()
+  "Insert a new BibTeX @Book entry; see also `bibtex-entry'."
+  (interactive)
+  (bibtex-entry "Book"))
+
+(defun bibtex-Booklet ()
+  "Insert a new BibTeX @Booklet entry; see also `bibtex-entry'."
+  (interactive)
+  (bibtex-entry "Booklet"))
+
+(defun bibtex-InBook ()
+  "Insert a new BibTeX @InBook entry; see also `bibtex-entry'."
+  (interactive)
+  (bibtex-entry "InBook"))
+
+(defun bibtex-InCollection ()
+  "Insert a new BibTeX @InCollection entry; see also `bibtex-entry'."
+  (interactive)
+  (bibtex-entry "InCollection"))
+
+(defun bibtex-InProceedings ()
+  "Insert a new BibTeX @InProceedings entry; see also `bibtex-entry'."
+  (interactive)
+  (bibtex-entry "InProceedings"))
+
+(defun bibtex-Manual ()
+  "Insert a new BibTeX @Manual entry; see also `bibtex-entry'."
+  (interactive)
+  (bibtex-entry "Manual"))
+
+(defun bibtex-MastersThesis ()
+  "Insert a new BibTeX @MastersThesis entry; see also `bibtex-entry'."
+  (interactive)
+  (bibtex-entry "MastersThesis"))
+
+(defun bibtex-Misc ()
+  "Insert a new BibTeX @Misc entry; see also `bibtex-entry'."
+  (interactive)
+  (bibtex-entry "Misc"))
+
+(defun bibtex-PhdThesis ()
+  "Insert a new BibTeX @PhdThesis entry; see also `bibtex-entry'."
+  (interactive)
+  (bibtex-entry "PhdThesis"))
+
+(defun bibtex-Proceedings ()
+  "Insert a new BibTeX @Proceedings entry; see also `bibtex-entry'."
+  (interactive)
+  (bibtex-entry "Proceedings"))
+
+(defun bibtex-TechReport ()
+  "Insert a new BibTeX @TechReport entry; see also `bibtex-entry'."
+  (interactive)
+  (bibtex-entry "TechReport"))
+
+(defun bibtex-Unpublished ()
+  "Insert a new BibTeX @Unpublished entry; see also `bibtex-entry'."
+  (interactive)
+  (bibtex-entry "Unpublished"))
+
+(defun bibtex-String ()
+  "Insert a new BibTeX @String entry."
+  (interactive)
+  (if (not bibtex-reference-keys)
+      (bibtex-parse-keys nil t))
+  (let ((key
+         (if (and
+              bibtex-maintain-sorted-entries
+              (not bibtex-sort-ignore-string-entries))
+             (completing-read
+              "String key: " bibtex-reference-keys nil nil nil 'bibtex-key-history))))
+    (if (and
+         bibtex-maintain-sorted-entries
+         (not bibtex-sort-ignore-string-entries))
+       (bibtex-find-entry-location key)
+      (bibtex-move-outside-of-entry))
+    (indent-to-column bibtex-entry-offset)
+    (insert
+     (concat
+      "@String"
+      (bibtex-entry-left-delimiter)
+      (if (and
+           bibtex-maintain-sorted-entries
+           (not bibtex-sort-ignore-string-entries))
+          key)
+      " = "
+      (bibtex-field-left-delimiter)
+      (bibtex-field-right-delimiter)
+      (bibtex-entry-right-delimiter)
+      "\n"))
+  (forward-line -1)
+  (forward-char
+   (if (and
+        bibtex-maintain-sorted-entries
+        (not bibtex-sort-ignore-string-entries))
+       (+ (length "@String{") (length key) (length " = {"))
+     (length "@String{")))))
+
+(defun bibtex-Preamble ()
+  "Insert a new BibTeX @Preamble entry."
+  (interactive)
+  (bibtex-move-outside-of-entry)
+  (indent-to-column bibtex-entry-offset)
+  (insert
+   "@Preamble"
+   (bibtex-entry-left-delimiter)
+   (bibtex-entry-right-delimiter)
+   "\n")
+  (forward-line -1)
+  (forward-char 10))
+
+\f
+;; Make BibTeX a Feature
+
+(provide 'bibtex)
+
+;;; bibtex.el ends here
diff --git a/emacs_el/cperl-mode.el b/emacs_el/cperl-mode.el
new file mode 100644 (file)
index 0000000..a0394a9
--- /dev/null
@@ -0,0 +1,8464 @@
+;;; cperl-mode.el --- Perl code editing commands for Emacs\r
+\r
+;; Copyright (C) 1985, 86, 87, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000, 2003\r
+;;     Free Software Foundation, Inc.\r
+\r
+;; Author: Ilya Zakharevich and Bob Olson\r
+;; Maintainer: Ilya Zakharevich <cperl@ilyaz.org>\r
+;; Keywords: languages, Perl\r
+\r
+;; This file is part of GNU Emacs.\r
+\r
+;;; This code started from the following message of long time ago\r
+;;; (IZ), but Bob does not maintain this mode any more:\r
+\r
+;;; From: olson@mcs.anl.gov (Bob Olson)\r
+;;; Newsgroups: comp.lang.perl\r
+;;; Subject: cperl-mode: Another perl mode for Gnuemacs\r
+;;; Date: 14 Aug 91 15:20:01 GMT\r
+\r
+;; Copyright (C) Ilya Zakharevich and Bob Olson\r
+\r
+;; This file may be distributed\r
+;; either under the same terms as GNU Emacs, or under the same terms\r
+;; as Perl. You should have received a copy of Perl Artistic license\r
+;; along with the Perl distribution.\r
+\r
+;; GNU Emacs is free software; you can redistribute it and/or modify\r
+;; it under the terms of the GNU General Public License as published by\r
+;; the Free Software Foundation; either version 2, or (at your option)\r
+;; any later version.\r
+\r
+;; GNU Emacs is distributed in the hope that it will be useful,\r
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+;; GNU General Public License for more details.\r
+\r
+;; You should have received a copy of the GNU General Public License\r
+;; along with GNU Emacs; see the file COPYING.  If not, write to the\r
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,\r
+;; Boston, MA 02111-1307, USA.\r
+\r
+;;; Corrections made by Ilya Zakharevich cperl@ilyaz.org\r
+;;; XEmacs changes by Peter Arius arius@informatik.uni-erlangen.de\r
+\r
+;;; Commentary:\r
+\r
+;; $Id: cperl-mode.el,v 5.0 2003/02/17 01:33:20 vera Exp vera $\r
+\r
+;;; If your Emacs does not default to `cperl-mode' on Perl files:\r
+;;; To use this mode put the following into\r
+;;; your .emacs file:\r
+\r
+;; (autoload 'perl-mode "cperl-mode" "alternate mode for editing Perl programs" t)\r
+\r
+;; You can either fine-tune the bells and whistles of this mode or\r
+;; bulk enable them by putting\r
+\r
+;; (setq cperl-hairy t)\r
+\r
+;; in your .emacs file.  (Emacs rulers do not consider it politically\r
+;; correct to make whistles enabled by default.)\r
+\r
+;; DO NOT FORGET to read micro-docs (available from `Perl' menu)   <<<<<<\r
+;; or as help on variables `cperl-tips', `cperl-problems',         <<<<<<\r
+;; `cperl-non-problems', `cperl-praise', `cperl-speed'.            <<<<<<\r
+\r
+;; Additional useful commands to put into your .emacs file (before\r
+;; RMS Emacs 20.3):\r
+\r
+;; (setq auto-mode-alist\r
+;;      (append '(("\\.\\([pP][Llm]\\|al\\)$" . perl-mode))  auto-mode-alist ))\r
+;; (setq interpreter-mode-alist (append interpreter-mode-alist\r
+;;                                     '(("miniperl" . perl-mode))))\r
+\r
+;; The mode information (on C-h m) provides some customization help.\r
+;; If you use font-lock feature of this mode, it is advisable to use\r
+;; either lazy-lock-mode or fast-lock-mode.  I prefer lazy-lock.\r
+\r
+;; Faces used now: three faces for first-class and second-class keywords\r
+;; and control flow words, one for each: comments, string, labels,\r
+;; functions definitions and packages, arrays, hashes, and variable\r
+;; definitions.  If you do not see all these faces, your font-lock does\r
+;; not define them, so you need to define them manually.\r
+;; Maybe you have an obsolete font-lock from 19.28 or earlier.  Upgrade.\r
+\r
+;; If you have a grayscale monitor, and do not have the variable\r
+;; font-lock-display-type bound to 'grayscale, insert\r
+\r
+;; (setq font-lock-display-type 'grayscale)\r
+\r
+;; into your .emacs file (this is relevant before RMS Emacs 20).\r
+\r
+;; This mode supports font-lock, imenu and mode-compile.  In the\r
+;; hairy version font-lock is on, but you should activate imenu\r
+;; yourself (note that mode-compile is not standard yet).  Well, you\r
+;; can use imenu from keyboard anyway (M-x imenu), but it is better\r
+;; to bind it like that:\r
+\r
+;; (define-key global-map [M-S-down-mouse-3] 'imenu)\r
+\r
+;;; Font lock bugs as of v4.32:\r
+\r
+;; The following kinds of Perl code erroneously start strings:\r
+;; \$`  \$'  \$"\r
+;; $opt::s  $opt_s  $opt{s}  (s => ...)  /\s+.../\r
+;; likewise with m, tr, y, q, qX instead of s\r
+\r
+;;; In fact the version of font-lock that this version supports can be\r
+;;; much newer than the version you actually have. This means that a\r
+;;; lot of faces can be set up, but are not visible on your screen\r
+;;; since the coloring rules for this faces are not defined.\r
+\r
+;;; Updates: ========================================\r
+\r
+;;; Made less hairy by default: parentheses not electric,\r
+;;; linefeed not magic. Bug with abbrev-mode corrected.\r
+\r
+;;;; After 1.4:\r
+;;;  Better indentation:\r
+;;;  subs inside braces should work now,\r
+;;;  Toplevel braces obey customization.\r
+;;;  indent-for-comment knows about bad cases, cperl-indent-for-comment\r
+;;;  moves cursor to a correct place.\r
+;;;  cperl-indent-exp written from the scratch! Slow... (quadratic!) :-(\r
+;;;        (50 secs on DB::DB (sub of 430 lines), 486/66)\r
+;;;  Minor documentation fixes.\r
+;;;  Imenu understands packages as prefixes (including nested).\r
+;;;  Hairy options can be switched off one-by-one by setting to null.\r
+;;;  Names of functions and variables changed to conform to `cperl-' style.\r
+\r
+;;;; After 1.5:\r
+;;;  Some bugs with indentation of labels (and embedded subs) corrected.\r
+;;;  `cperl-indent-region' done (slow :-()).\r
+;;;  `cperl-fill-paragraph' done.\r
+;;;  Better package support for `imenu'.\r
+;;;  Progress indicator for indentation (with `imenu' loaded).\r
+;;;  `Cperl-set' was busted, now setting the individual hairy option\r
+;;;     should be better.\r
+\r
+;;;; After 1.6:\r
+;;; `cperl-set-style' done.\r
+;;; `cperl-check-syntax' done.\r
+;;; Menu done.\r
+;;; New config variables `cperl-close-paren-offset' and `cperl-comment-column'.\r
+;;; Bugs with `cperl-auto-newline' corrected.\r
+;;; `cperl-electric-lbrace' can work with `cperl-auto-newline' in situation\r
+;;; like $hash{.\r
+\r
+;;;; 1.7 XEmacs (arius@informatik.uni-erlangen.de):\r
+;;; - use `next-command-event', if `next-command-events' does not exist\r
+;;; - use `find-face' as def. of `is-face'\r
+;;; - corrected def. of `x-color-defined-p'\r
+;;; - added const defs for font-lock-comment-face,\r
+;;;   font-lock-keyword-face and font-lock-function-name-face\r
+;;; - added def. of font-lock-variable-name-face\r
+;;; - added (require 'easymenu) inside an `eval-when-compile'\r
+;;; - replaced 4-argument `substitute-key-definition' with ordinary\r
+;;;   `define-key's\r
+;;; - replaced `mark-active' in menu definition by `cperl-use-region-p'.\r
+;;; Todo (at least):\r
+;;; - use emacs-vers.el (http://www.cs.utah.edu/~eeide/emacs/emacs-vers.el.gz)\r
+;;;   for portable code?\r
+;;; - should `cperl-mode' do a\r
+;;;    (if (featurep 'easymenu) (easy-menu-add cperl-menu))\r
+;;;   or should this be left to the user's `cperl-mode-hook'?\r
+\r
+;;; Some bugs introduced by the above fix corrected (IZ ;-).\r
+;;; Some bugs under XEmacs introduced by the correction corrected.\r
+\r
+;;; Some more can remain since there are two many different variants.\r
+;;; Please feedback!\r
+\r
+;;; We do not support fontification of arrays and hashes under\r
+;;; obsolete font-lock any more. Upgrade.\r
+\r
+;;;; after 1.8 Minor bug with parentheses.\r
+;;;; after 1.9 Improvements from Joe Marzot.\r
+;;;; after 1.10\r
+;;;  Does not need easymenu to compile under XEmacs.\r
+;;;  `vc-insert-headers' should work better.\r
+;;;  Should work with 19.29 and 19.12.\r
+;;;  Small improvements to fontification.\r
+;;;  Expansion of keywords does not depend on C-? being backspace.\r
+\r
+;;; after 1.10+\r
+;;; 19.29 and 19.12 supported.\r
+;;; `cperl-font-lock-enhanced' deprecated. Use font-lock-extra.el.\r
+;;; Support for font-lock-extra.el.\r
+\r
+;;;; After 1.11:\r
+;;; Tools submenu.\r
+;;; Support for perl5-info.\r
+;;; `imenu-go-find-at-position' in Tools requires imenu-go.el (see hints above)\r
+;;; Imenu entries do not work with stock imenu.el. Patch sent to maintainers.\r
+;;; Fontifies `require a if b;', __DATA__.\r
+;;; Arglist for auto-fill-mode was incorrect.\r
+\r
+;;;; After 1.12:\r
+;;; `cperl-lineup-step' and `cperl-lineup' added: lineup constructions\r
+;;; vertically.\r
+;;; `cperl-do-auto-fill' updated for 19.29 style.\r
+;;; `cperl-info-on-command' now has a default.\r
+;;; Workaround for broken C-h on XEmacs.\r
+;;; VC strings escaped.\r
+;;; C-h f now may prompt for function name instead of going on,\r
+;;; controlled by `cperl-info-on-command-no-prompt'.\r
+\r
+;;;; After 1.13:\r
+;;; Msb buffer list includes perl files\r
+;;; Indent-for-comment uses indent-to\r
+;;; Can write tag files using etags.\r
+\r
+;;;; After 1.14:\r
+;;; Recognizes (tries to ;-) {...} which are not blocks during indentation.\r
+;;; `cperl-close-paren-offset' affects ?\] too (and ?\} if not block)\r
+;;; Bug with auto-filling comments started with "##" corrected.\r
+\r
+;;;; Very slow now: on DB::DB 0.91, 486/66:\r
+\r
+;;;Function Name                             Call Count  Elapsed Time  Average Time\r
+;;;========================================  ==========  ============  ============\r
+;;;cperl-block-p                             469         3.7799999999  0.0080597014\r
+;;;cperl-get-state                           505         163.39000000  0.3235445544\r
+;;;cperl-comment-indent                      12          0.0299999999  0.0024999999\r
+;;;cperl-backward-to-noncomment              939         4.4599999999  0.0047497337\r
+;;;cperl-calculate-indent                    505         172.22000000  0.3410297029\r
+;;;cperl-indent-line                         505         172.88000000  0.3423366336\r
+;;;cperl-use-region-p                        40          0.0299999999  0.0007499999\r
+;;;cperl-indent-exp                          1           177.97000000  177.97000000\r
+;;;cperl-to-comment-or-eol                   1453        3.9800000000  0.0027391603\r
+;;;cperl-backward-to-start-of-continued-exp  9           0.0300000000  0.0033333333\r
+;;;cperl-indent-region                       1           177.94000000  177.94000000\r
+\r
+;;;; After 1.15:\r
+;;; Takes into account white space after opening parentheses during indent.\r
+;;; May highlight pods and here-documents: see `cperl-pod-here-scan',\r
+;;; `cperl-pod-here-fontify', `cperl-pod-face'. Does not use this info\r
+;;; for indentation so far.\r
+;;; Fontification updated to 19.30 style.\r
+;;; The change 19.29->30 did not add all the required functionality,\r
+;;;     but broke "font-lock-extra.el". Get "choose-color.el" from\r
+;;;       ftp://ftp.math.ohio-state.edu/pub/users/ilya/emacs\r
+\r
+;;;; After 1.16:\r
+;;;       else # comment\r
+;;;    recognized as a start of a block.\r
+;;;  Two different font-lock-levels provided.\r
+;;;  `cperl-pod-head-face' introduced. Used for highlighting.\r
+;;;  `imenu' marks pods, +Packages moved to the head.\r
+\r
+;;;; After 1.17:\r
+;;;  Scan for pods highlights here-docs too.\r
+;;;  Note that the tag of here-doc may be rehighlighted later by lazy-lock.\r
+;;;  Only one here-doc-tag per line is supported, and one in comment\r
+;;;  or a string may break fontification.\r
+;;;  POD headers were supposed to fill one line only.\r
+\r
+;;;; After 1.18:\r
+;;;  `font-lock-keywords' were set in 19.30 style _always_. Current scheme\r
+;;;    may  break under XEmacs.\r
+;;;  `cperl-calculate-indent' dis suppose that `parse-start' was defined.\r
+;;;  `fontified' tag is added to fontified text as well as `lazy-lock' (for\r
+;;;    compatibility with older lazy-lock.el) (older one overfontifies\r
+;;;    something nevertheless :-().\r
+;;;  Will not indent something inside pod and here-documents.\r
+;;;  Fontifies the package name after import/no/bootstrap.\r
+;;;  Added new entry to menu with meta-info about the mode.\r
+\r
+;;;; After 1.19:\r
+;;;  Prefontification works much better with 19.29. Should be checked\r
+;;;   with 19.30 as well.\r
+;;;  Some misprints in docs corrected.\r
+;;;  Now $a{-text} and -text => "blah" are fontified as strings too.\r
+;;;  Now the pod search is much stricter, so it can help you to find\r
+;;;    pod sections which are broken because of whitespace before =blah\r
+;;;    - just observe the fontification.\r
+\r
+;;;; After 1.20\r
+;;;  Anonymous subs are indented with respect to the level of\r
+;;;    indentation of `sub' now.\r
+;;;  {} is recognized as hash after `bless' and `return'.\r
+;;;  Anonymous subs are split by `cperl-linefeed' as well.\r
+;;;  Electric parens embrace a region if present.\r
+;;;  To make `cperl-auto-newline' useful,\r
+;;;    `cperl-auto-newline-after-colon' is introduced.\r
+;;;  `cperl-electric-parens' is now t or nul. The old meaning is moved to\r
+;;;  `cperl-electric-parens-string'.\r
+;;;  `cperl-toggle-auto-newline' introduced, put on C-c C-a.\r
+;;;  `cperl-toggle-abbrev' introduced, put on C-c C-k.\r
+;;;  `cperl-toggle-electric' introduced, put on C-c C-e.\r
+;;;  Beginning-of-defun-regexp was not anchored.\r
+\r
+;;;; After 1.21\r
+;;;  Auto-newline grants `cperl-extra-newline-before-brace' if "{" is typed\r
+;;;    after ")".\r
+;;;  {} is recognized as expression after `tr' and friends.\r
+\r
+;;;; After 1.22\r
+;;;  Entry Hierarchy added to imenu. Very primitive so far.\r
+;;;  One needs newer `imenu-go'.el. A patch to `imenu' is needed as well.\r
+;;;  Writes its own TAGS files.\r
+;;;  Class viewer based on TAGS files. Does not trace @ISA so far.\r
+;;;  19.31: Problems with scan for PODs corrected.\r
+;;;  First POD header correctly fontified.\r
+;;;  I needed (setq imenu-use-keymap-menu t) to get good imenu in 19.31.\r
+;;;  Apparently it makes a lot of hierarchy code obsolete...\r
+\r
+;;;; After 1.23\r
+;;;  Tags filler now scans *.xs as well.\r
+;;;  The info from *.xs scan is used by the hierarchy viewer.\r
+;;;  Hierarchy viewer documented.\r
+;;;  Bug in 19.31 imenu documented.\r
+\r
+;;;; After 1.24\r
+;;;  New location for info-files mentioned,\r
+;;;  Electric-; should work better.\r
+;;;  Minor bugs with POD marking.\r
+\r
+;;;; After 1.25 (probably not...)\r
+;;;  `cperl-info-page' introduced.\r
+;;;  To make `uncomment-region' working, `comment-region' would\r
+;;;  not insert extra space.\r
+;;;  Here documents delimiters better recognized\r
+;;;  (empty one, and non-alphanums in quotes handled). May be wrong with 1<<14?\r
+;;;  `cperl-db' added, used in menu.\r
+;;;  imenu scan removes text-properties, for better debugging\r
+;;;    - but the bug is in 19.31 imenu.\r
+;;;  formats highlighted by font-lock and prescan, embedded comments\r
+;;;  are not treated.\r
+;;;  POD/friends scan merged in one pass.\r
+;;;  Syntax class is not used for analyzing the code, only char-syntax\r
+;;;  may be checked against _ or'ed with w.\r
+;;;  Syntax class of `:' changed to be _.\r
+;;;  `cperl-find-bad-style' added.\r
+\r
+;;;; After 1.25\r
+;;;  When search for here-documents, we ignore commented << in simplest cases.\r
+;;;  `cperl-get-help' added, available on C-h v and from menu.\r
+;;;  Auto-help added. Default with `cperl-hairy', switchable on/off\r
+;;;   with startup variable `cperl-lazy-help-time' and from\r
+;;;   menu. Requires `run-with-idle-timer'.\r
+;;;  Highlighting of @abc{@efg} was wrong - interchanged two regexps.\r
+\r
+;;;; After 1.27\r
+;;;  Indentation: At toplevel after a label - fixed.\r
+;;;  1.27 was put to archives in binary mode ===> DOSish :-(\r
+\r
+;;;; After 1.28\r
+;;;  Thanks to Martin Buchholz <mrb@Eng.Sun.COM>: misprints in\r
+;;;  comments and docstrings corrected, XEmacs support cleaned up.\r
+;;;  The closing parenths would enclose the region into matching\r
+;;;  parens under the same conditions as the opening ones.\r
+;;;  Minor updates to `cperl-short-docs'.\r
+;;;  Will not consider <<= as start of here-doc.\r
+\r
+;;;; After 1.29\r
+;;;  Added an extra advice to look into Micro-docs. ;-).\r
+;;;  Enclosing of region when you press a closing parenth is regulated by\r
+;;;  `cperl-electric-parens-string'.\r
+;;;  Minor updates to `cperl-short-docs'.\r
+;;;  `initialize-new-tags-table' called only if present (Does this help\r
+;;;     with generation of tags under XEmacs?).\r
+;;;  When creating/updating tag files, new info is written at the old place,\r
+;;;     or at the end (is this a wanted behaviour? I need this in perl build directory).\r
+\r
+;;;; After 1.30\r
+;;;  All the keywords from keywords.pl included (maybe with dummy explanation).\r
+;;;  No auto-help inside strings, comment, here-docs, formats, and pods.\r
+;;;  Shrinkwrapping of info, regulated by `cperl-max-help-size',\r
+;;;  `cperl-shrink-wrap-info-frame'.\r
+;;;  Info on variables as well.\r
+;;;  Recognision of HERE-DOCS improved yet more.\r
+;;;  Autonewline works on `}' without warnings.\r
+;;;  Autohelp works again on $_[0].\r
+\r
+;;;; After 1.31\r
+;;;  perl-descr.el found its author - hi, Johan!\r
+;;;  Some support for correct indent after here-docs and friends (may\r
+;;;  be superseeded by eminent change to Emacs internals).\r
+;;;  Should work with older Emaxen as well ( `-style stuff removed).\r
+\r
+;;;; After 1.32\r
+\r
+;;;  Started to add support for `syntax-table' property (should work\r
+;;;  with patched Emaxen), controlled by\r
+;;;  `cperl-use-syntax-table-text-property'. Currently recognized:\r
+;;;    All quote-like operators: m, s, y, tr, qq, qw, qx, q,\r
+;;;    // in most frequent context:\r
+;;;          after block or\r
+;;;                    ~ { ( = | & + - * ! , ;\r
+;;;          or\r
+;;;                    while if unless until and or not xor split grep map\r
+;;;    Here-documents, formats, PODs,\r
+;;;    ${...}\r
+;;;    'abc$'\r
+;;;    sub a ($); sub a ($) {}\r
+;;;  (provide 'cperl-mode) was missing!\r
+;;;  `cperl-after-expr-p' is now much smarter after `}'.\r
+;;;  `cperl-praise' added to mini-docs.\r
+;;;  Utilities try to support subs-with-prototypes.\r
+\r
+;;;; After 1.32.1\r
+;;;  `cperl-after-expr-p' is now much smarter after "() {}" and "word {}":\r
+;;;     if word is "else, map, grep".\r
+;;;  Updated for new values of syntax-table constants.\r
+;;;  Uses `help-char' (at last!) (disabled, does not work?!)\r
+;;;  A couple of regexps where missing _ in character classes.\r
+;;;  -s could be considered as start of regexp, 1../blah/ was not,\r
+;;;  as was not /blah/ at start of file.\r
+\r
+;;;; After 1.32.2\r
+;;;  "\C-hv" was wrongly "\C-hf"\r
+;;;  C-hv was not working on `[index()]' because of [] in skip-chars-*.\r
+;;;  `__PACKAGE__' supported.\r
+;;;  Thanks for Greg Badros: `cperl-lazy-unstall' is more complete,\r
+;;;  `cperl-get-help' is made compatible with `query-replace'.\r
+\r
+;;;; As of Apr 15, development version of 19.34 supports\r
+;;;; `syntax-table' text properties. Try setting\r
+;;;; `cperl-use-syntax-table-text-property'.\r
+\r
+;;;; After 1.32.3\r
+;;;  We scan for s{}[] as well (in simplest situations).\r
+;;;  We scan for $blah'foo as well.\r
+;;;  The default is to use `syntax-table' text property if Emacs is good enough.\r
+;;;  `cperl-lineup' is put on C-M-| (=C-M-S-\\).\r
+;;;  Start of `cperl-beautify-regexp'.\r
+\r
+;;;; After 1.32.4\r
+;;; `cperl-tags-hier-init' did not work in text-mode.\r
+;;; `cperl-noscan-files-regexp' had a misprint.\r
+;;; Generation of Class Hierarchy was broken due to a bug in `x-popup-menu'\r
+;;;  in 19.34.\r
+\r
+;;;; After 1.33:\r
+;;; my,local highlight vars after {} too.\r
+;;; TAGS could not be created before imenu was loaded.\r
+;;; `cperl-indent-left-aligned-comments' created.\r
+;;; Logic of `cperl-indent-exp' changed a little bit, should be more\r
+;;;  robust w.r.t. multiline strings.\r
+;;; Recognition of blah'foo takes into account strings.\r
+;;; Added '.al' to the list of Perl extensions.\r
+;;; Class hierarchy is "mostly" sorted (need to rethink algorthm\r
+;;;  of pruning one-root-branch subtrees to get yet better sorting.)\r
+;;; Regeneration of TAGS was busted.\r
+;;; Can use `syntax-table' property when generating TAGS\r
+;;;  (governed by  `cperl-use-syntax-table-text-property-for-tags').\r
+\r
+;;;; After 1.35:\r
+;;; Can process several =pod/=cut sections one after another.\r
+;;; Knows of `extproc' when under `emx', indents with `__END__' and `__DATA__'.\r
+;;; `cperl-under-as-char' implemented (XEmacs people like broken behaviour).\r
+;;; Beautifier for regexps fixed.\r
+;;; `cperl-beautify-level', `cperl-contract-level' coded\r
+;;;\r
+;;;; Emacs's 20.2 problems:\r
+;;; `imenu.el' has bugs, `imenu-add-to-menubar' does not work.\r
+;;; Couple of others problems with 20.2 were reported, my ability to check/fix\r
+;;; them is very reduced now.\r
+\r
+;;;; After 1.36:\r
+;;;  'C-M-|' in XEmacs fixed\r
+\r
+;;;; After 1.37:\r
+;;;  &&s was not recognized as start of regular expression;\r
+;;;  Will "preprocess" the contents of //e part of s///e too;\r
+;;;  What to do with s# blah # foo #e ?\r
+;;;  Should handle s;blah;foo;; better.\r
+;;;  Now the only known problems with regular expression recognition:\r
+;;;;;;;  s<foo>/bar/   - different delimiters (end ignored)\r
+;;;;;;;  s/foo/\\bar/  - backslash at start of subst (made into one chunk)\r
+;;;;;;;  s/foo//       - empty subst (made into one chunk + '/')\r
+;;;;;;;  s/foo/(bar)/  - start-group at start of subst (internal group will not match backwards)\r
+\r
+;;;; After 1.38:\r
+;;;  We highlight closing / of s/blah/foo/e;\r
+;;;  This handles s# blah # foo #e too;\r
+;;;  s//blah/, s///, s/blah// works again, and s#blah## too, the algorithm\r
+;;;   is much simpler now;\r
+;;;  Next round of changes: s\\\ works, s<blah>/foo/,\r
+;;;   comments between the first and the second part allowed\r
+;;;  Another problem discovered:\r
+;;;;;;;  s[foo] <blah>e        - e part delimited by different <> (will not match)\r
+;;;  `cperl-find-pods-heres' somehow maybe called when string-face is undefined\r
+;;;   - put a stupid workaround for 20.1\r
+\r
+;;;; After 1.39:\r
+;;;  Could indent here-docs for comments;\r
+;;;  These problems fixed:\r
+;;;;;;;  s/foo/\\bar/  - backslash at start of subst (made into two chunk)\r
+;;;;;;;  s[foo] <blah>e        - "e" part delimited by "different" <> (will match)\r
+;;;  Matching brackets honor prefices, may expand abbreviations;\r
+;;;  When expanding abbrevs, will remove last char only after\r
+;;;    self-inserted whitespace;\r
+;;;  More convenient "Refress hard constructs" in menu;\r
+;;;  `cperl-add-tags-recurse', `cperl-add-tags-recurse-noxs'\r
+;;;    added (for -batch mode);\r
+;;;  Better handling of errors when scanning for Perl constructs;\r
+;;;;;;;  Possible "problem" with class hierarchy in Perl distribution\r
+;;;;;;;    directory: ./ext duplicates ./lib;\r
+;;;  Write relative paths for generated TAGS;\r
+\r
+;;;; After 1.40:\r
+;;;  s  /// may be separated by "\n\f" too;\r
+;;;  `s  #blah' recognized as a comment;\r
+;;;  Would highlight s/abc//s wrong;\r
+;;;  Debugging code in `cperl-electric-keywords' was leaking a message;\r
+\r
+;;;; After 1.41:\r
+;;;  RMS changes for 20.3 merged\r
+\r
+;;;; 2.0.1.0: RMS mode (has 3 misprints)\r
+\r
+;;;; After 2.0:\r
+;;;  RMS whitespace changes for 20.3 merged\r
+\r
+;;;; After 2.1:\r
+;;;  History updated\r
+\r
+;;;; After 2.2:\r
+;;;  Merge `c-style-alist' since `c-mode' is no more.  (Somebody who\r
+;;;    uses the styles should check that they work OK!)\r
+;;;  All the variable warnings go away, some undef functions too.\r
+\r
+;;;; After 2.3:\r
+;;;  Added `cperl-perldoc' (thanks to Anthony Foiani <afoiani@uswest.com>)\r
+;;;  Added `cperl-pod-to-manpage' (thanks to Nick Roberts <Nick.Roberts@src.bae.co.uk>)\r
+;;;  All the function warnings go away.\r
+\r
+;;;; After 2.4:\r
+;;;  `Perl doc', `Regexp' submenus created (latter to allow short displays).\r
+;;;  `cperl-clobber-lisp-bindings' added.\r
+;;;  $a->y() is not y///.\r
+;;;  `cperl-after-block-p' was missing a `save-excursion' => wrong results.\r
+;;;  `cperl-val' was defined too late.\r
+;;;  `cperl-init-faces' was failing.\r
+;;;  Init faces when loading `ps-print'.\r
+\r
+;;;; After 2.4:\r
+;;;  `cperl-toggle-autohelp' implemented.\r
+;;;  `while SPACE LESS' was buggy.\r
+;;;  `-text' in `[-text => 1]' was not highlighted.\r
+;;;  `cperl-after-block-p' was FALSE after `sub f {}'.\r
+\r
+;;;; After 2.5:\r
+;;;  `foreachmy', `formy' expanded too.\r
+;;;  Expand `=pod-directive'.\r
+;;;  `cperl-linefeed' behaves reasonable in POD-directive lines.\r
+;;;  `cperl-electric-keyword' prints a message, governed by\r
+;;;    `cperl-message-electric-keyword'.\r
+\r
+;;;; After 2.6:\r
+;;;  Typing `}' was not checking for being block or not.\r
+;;;  Beautifying levels in RE: Did not know about lookbehind;\r
+;;;                           finding *which* level was not intuitive;\r
+;;;                           `cperl-beautify-levels' added.\r
+;;;  Allow here-docs contain `=head1' and friends (at least for keywords).\r
+\r
+;;;; After 2.7:\r
+;;;  Fix for broken `font-lock-unfontify-region-function'.  Should\r
+;;;    preserve `syntax-table' properties even with `lazy-lock'.\r
+\r
+;;;; After 2.8:\r
+;;;  Some more compile time warnings crept in.\r
+;;;  `cperl-indent-region-fix-else' implemented.\r
+;;;  `cperl-fix-line-spacing' implemented.\r
+;;;  `cperl-invert-if-unless' implemented (C-c C-t and in Menu).\r
+;;;  Upgraded hints to mention 20.2's goods/bads.\r
+;;;  Started to use `cperl-extra-newline-before-brace-multiline',\r
+;;;    `cperl-break-one-line-blocks-when-indent',\r
+;;;    `cperl-fix-hanging-brace-when-indent', `cperl-merge-trailing-else'.\r
+\r
+;;;; After 2.9:\r
+;;;  Workaround for another `font-lock's `syntax-table' text-property bug.\r
+;;;  `zerop' could be applied to nil.\r
+;;;  At last, may work with `font-lock' without setting `cperl-font-lock'.\r
+;;;    (We expect that starting from 19.33, `font-lock' supports keywords\r
+;;;     being a function - what is a correct version?)\r
+;;;  Rename `cperl-indent-region-fix-else' to\r
+;;;    `cperl-indent-region-fix-constructs'.\r
+;;;  `cperl-fix-line-spacing' could be triggered inside strings, would not\r
+;;;     know what to do with BLOCKs of map/printf/etc.\r
+;;;  `cperl-merge-trailing-else' and `cperl-fix-line-spacing' handle\r
+;;;     `continue' too.\r
+;;;  Indentation after {BLOCK} knows about map/printf/etc.\r
+;;;  Finally: treat after-comma lines as continuation lines.\r
+\r
+;;;; After 2.10:\r
+;;;  `continue' made electric.\r
+;;;  Electric `do' inserts `do/while'.\r
+;;;  Some extra compile-time warnings crept in.\r
+;;;  `font-lock' of 19.33 could not handle font-lock-keywords being a function\r
+;;;      returning a symbol.\r
+\r
+;;;; After 2.11:\r
+;;;  Changes to make syntaxification to be autoredone via `font-lock'.\r
+;;;    Switched on by `cperl-syntaxify-by-font-lock', off by default so far.\r
+\r
+;;;; After 2.12:\r
+;;;  Remove some commented out chunks.\r
+;;;  Styles are slightly updated (a lot of work is needed, especially\r
+;;;    with new `cperl-fix-line-spacing').\r
+\r
+;;;; After 2.13:\r
+;;;  Old value of style is memorized when choosing a new style, may be\r
+;;;    restored from the same menu.\r
+;;;  Mode-documentation added to micro-docs.\r
+;;;  `cperl-praise' updated.\r
+;;;  `cperl-toggle-construct-fix' added on C-c C-w and menu.\r
+;;;  `auto-fill-mode' added on C-c C-f and menu.\r
+;;;  `PerlStyle' style added.\r
+;;;  Message for termination of scan corrected.\r
+\r
+;;;; After 2.14:\r
+\r
+;;;  Did not work with -q\r
+\r
+;;;; After 2.15:\r
+\r
+;;;  `cperl-speed' hints added.\r
+;;;  Minor style fixes.\r
+\r
+;;;; After 2.15:\r
+;;;  Make backspace electric after expansion of `else/continue' too.\r
+\r
+;;;; After 2.16:\r
+;;;  Starting to merge changes to RMS emacs version.\r
+\r
+;;;; After 2.17:\r
+;;;  Merged custom stuff and darn `font-lock-constant-face'.\r
+\r
+;;;; After 2.18:\r
+;;;  Bumped the version to 3.1\r
+\r
+;;;; After 3.1:\r
+;;;  Fixed customization to honor cperl-hairy.\r
+;;;  Created customization groups.  Sent to RMS to include into 2.3.\r
+\r
+;;;; After 3.2:\r
+;;;  Interaction of `font-lock-hot-pass' and `cperl-syntaxify-by-font-lock'.\r
+;;;  (`cperl-after-block-and-statement-beg'):\r
+;;;  (`cperl-after-block-p'):\r
+;;;  (`cperl-after-expr-p'):   It is BLOCK if we reach lim when backup sexp.\r
+;;;  (`cperl-indent-region'):  Make a marker for END - text added/removed.\r
+;;;  (`cperl-style-alist', `cperl-styles-entries')\r
+;;;            Include `cperl-merge-trailing-else' where the value is clear.\r
+\r
+;;;; After 3.3:\r
+;;;  (`cperl-tips'):\r
+;;;  (`cperl-problems'):       Improvements to docs.\r
+\r
+;;;; After 3.4:\r
+;;;  (`cperl-mode'):           Make lazy syntaxification possible.\r
+;;;  (`cperl-find-pods-heres'): Safe a position in buffer where it is safe to\r
+;;;                            restart syntaxification.\r
+;;;  (`cperl-syntaxify-by-font-lock'): Set to t, should be safe now.\r
+\r
+;;;; After 3.5:\r
+;;;  (`cperl-syntaxify-by-font-lock'): Better default, customizes to\r
+;;;                            `message' too.\r
+\r
+;;;; After 3.6:\r
+;;;  (`cperl-find-pods-heres'): changed so that -d ?foo? is a RE.\r
+;;;  (`cperl-array-face'): changed name from `font-lock-emphasized-face'.\r
+;;;  (`cperl-hash-face'): changed name from  `font-lock-other-emphasized-face'.\r
+;;;  Use `defface' to define these two extra faces.\r
+\r
+;;;; After 3.7:\r
+;;;  Can use linear algorithm for indentation if Emacs supports it:\r
+;;;  indenting DB::DB (800+ lines) improved from 69 sec to 11 sec\r
+;;;  (73 vs 15 with imenu).\r
+;;;  (`cperl-emacs-can-parse'):        New state.\r
+;;;  (`cperl-indent-line'):    Corrected to use global state.\r
+;;;  (`cperl-calculate-indent'):       Likewise.\r
+;;;  (`cperl-fix-line-spacing'):       Likewise (not used yet).\r
+\r
+;;;; After 3.8:\r
+;;;  (`cperl-choose-color'):   Converted to a function (to be compilable in text-mode).\r
+\r
+;;;; After 3.9:\r
+;;;  (`cperl-dark-background '):       Disable without window-system.\r
+\r
+;;;; After 3.10:\r
+;;;  Do `defface' only if window-system.\r
+\r
+;;;; After 3.11:\r
+;;;  (`cperl-fix-line-spacing'):       sped up to bail out early.\r
+;;;  (`cperl-indent-region'):  Disable hooks during the call (how to call them later?).\r
+\r
+;;;  Now indents 820-line-long function in 6.5 sec (including syntaxification) the first time\r
+;;;  (when buffer has few properties), 7.1 sec the second time.\r
+\r
+;;;Function Name                              Call Count  Elapsed Time  Average Time\r
+;;;=========================================  ==========  ============  ============\r
+;;;cperl-indent-exp                           1           10.039999999  10.039999999\r
+;;;cperl-indent-region                        1           10.0          10.0\r
+;;;cperl-indent-line                          821         6.2100000000  0.0075639464\r
+;;;cperl-calculate-indent                     821         5.0199999999  0.0061144945\r
+;;;cperl-backward-to-noncomment               2856        2.0500000000  0.0007177871\r
+;;;cperl-fontify-syntaxically                 2           1.78          0.8900000000\r
+;;;cperl-find-pods-heres                      2           1.78          0.8900000000\r
+;;;cperl-update-syntaxification               1           1.78          1.78\r
+;;;cperl-fix-line-spacing                     769         1.4800000000  0.0019245773\r
+;;;cperl-after-block-and-statement-beg        163         1.4100000000  0.0086503067\r
+;;;cperl-block-p                              775         1.1800000000  0.0015225806\r
+;;;cperl-to-comment-or-eol                    3652        1.1200000000  0.0003066812\r
+;;;cperl-after-block-p                        165         1.0500000000  0.0063636363\r
+;;;cperl-commentify                           141         0.22          0.0015602836\r
+;;;cperl-get-state                            813         0.16          0.0001968019\r
+;;;cperl-backward-to-start-of-continued-exp   26          0.12          0.0046153846\r
+;;;cperl-delay-update-hook                    2107        0.0899999999  4.271...e-05\r
+;;;cperl-protect-defun-start                  141         0.0700000000  0.0004964539\r
+;;;cperl-after-label                          407         0.0599999999  0.0001474201\r
+;;;cperl-forward-re                           139         0.0299999999  0.0002158273\r
+;;;cperl-comment-indent                       26          0.0299999999  0.0011538461\r
+;;;cperl-use-region-p                         8           0.0           0.0\r
+;;;cperl-lazy-hook                            15          0.0           0.0\r
+;;;cperl-after-expr-p                         8           0.0           0.0\r
+;;;cperl-font-lock-unfontify-region-function  1           0.0           0.0\r
+\r
+;;;Function Name                              Call Count  Elapsed Time  Average Time\r
+;;;=========================================  ==========  ============  ============\r
+;;;cperl-fix-line-spacing                     769         1.4500000000  0.0018855656\r
+;;;cperl-indent-line                          13          0.3100000000  0.0238461538\r
+;;;cperl-after-block-and-statement-beg        69          0.2700000000  0.0039130434\r
+;;;cperl-after-block-p                        69          0.2099999999  0.0030434782\r
+;;;cperl-calculate-indent                     13          0.1000000000  0.0076923076\r
+;;;cperl-backward-to-noncomment               177         0.0700000000  0.0003954802\r
+;;;cperl-get-state                            13          0.0           0.0\r
+;;;cperl-to-comment-or-eol                    179         0.0           0.0\r
+;;;cperl-get-help-defer                       1           0.0           0.0\r
+;;;cperl-lazy-hook                            11          0.0           0.0\r
+;;;cperl-after-expr-p                         2           0.0           0.0\r
+;;;cperl-block-p                              13          0.0           0.0\r
+;;;cperl-after-label                          5           0.0           0.0\r
+\r
+;;;; After 3.12:\r
+;;;  (`cperl-find-pods-heres'): do not warn on `=cut' if doing a chunk only.\r
+\r
+;;;; After 3.13:\r
+;;;  (`cperl-mode'): load pseudo-faces on `cperl-find-pods-heres' (for 19.30).\r
+;;;  (`x-color-defined-p'): was not compiling on XEmacs\r
+;;;  (`cperl-find-pods-heres'): 1 << 6 was OK, but 1<<6 was considered as HERE\r
+;;;                             <file/glob> made into a string.\r
+\r
+;;;; After 3.14:\r
+;;;  (`cperl-find-pods-heres'): Postpone addition of faces after syntactic step\r
+;;;                            Recognition of <FH> was wrong.\r
+;;;  (`cperl-clobber-lisp-bindings'): if set, C-c variants are the old ones\r
+;;;  (`cperl-unwind-to-safe'): New function.\r
+;;;  (`cperl-fontify-syntaxically'): Use `cperl-unwind-to-safe' to start at reasonable position.\r
+\r
+;;;; After 3.15:\r
+;;;  (`cperl-forward-re'):     Highlight the trailing / in s/foo// as string.\r
+;;;                    Highlight the starting // in s//foo/ as function-name.\r
+\r
+;;;; After 3.16:\r
+;;;  (`cperl-find-pods-heres'): Highlight `gem' in s///gem as a keyword.\r
+\r
+;;;; After 4.0:\r
+;;;  (`cperl-find-pods-heres'): `qr' added\r
+;;;  (`cperl-electric-keyword'):       Likewise\r
+;;;  (`cperl-electric-else'):          Likewise\r
+;;;  (`cperl-to-comment-or-eol'):      Likewise\r
+;;;  (`cperl-make-regexp-x'):  Likewise\r
+;;;  (`cperl-init-faces'):     Likewise, and `lock' (as overridable?).\r
+;;;  (`cperl-find-pods-heres'): Knows that split// is null-RE.\r
+;;;                            Highlights separators in 3-parts expressions\r
+;;;                            as labels.\r
+\r
+;;;; After 4.1:\r
+;;;  (`cperl-find-pods-heres'):        <> was considered as a glob\r
+;;;  (`cperl-syntaxify-unwind'): New configuration variable\r
+;;;  (`cperl-fontify-m-as-s'): New configuration variable\r
+\r
+;;;; After 4.2:\r
+;;;  (`cperl-find-pods-heres'): of the last line being `=head1' fixed.\r
+\r
+;;;  Handling of a long construct is still buggy if only the part of\r
+;;;  construct touches the updated region (we unwind to the start of\r
+;;;  long construct, but the end may have residual properties).\r
+\r
+;;;  (`cperl-unwind-to-safe'): would not go to beginning of buffer.\r
+;;;  (`cperl-electric-pod'):   check for after-expr was performed\r
+;;;                            inside of POD too.\r
+\r
+;;;; After 4.3:\r
+;;;  (`cperl-backward-to-noncomment'): better treatment of PODs and HEREs.\r
+\r
+;;;  Indent-line works good, but indent-region does not - at toplevel...\r
+;;;  (`cperl-unwind-to-safe'): Signature changed.\r
+;;;  (`x-color-defined-p'):     was defmacro'ed with a tick.  Remove another def.\r
+;;;  (`cperl-clobber-mode-lists'): New configuration variable.\r
+;;;  (`cperl-array-face'): One of definitions was garbled.\r
+\r
+;;;; After 4.4:\r
+;;;  (`cperl-not-bad-style-regexp'):   Updated.\r
+;;;  (`cperl-make-regexp-x'):  Misprint in a message.\r
+;;;  (`cperl-find-pods-heres'):        $a-1 ? foo : bar; was a regexp.\r
+;;;                             `<< (' was considered a start of POD.\r
+;;;  Init:                     `cperl-is-face' was busted.\r
+;;;  (`cperl-make-face'):      New macros.\r
+;;;  (`cperl-force-face'):     New macros.\r
+;;;  (`cperl-init-faces'):     Corrected to use new macros;\r
+;;;                            `if' for copying `reference-face' to\r
+;;;                            `constant-face' was backward.\r
+;;;  (`font-lock-other-type-face'): Done via `defface' too.\r
+\r
+;;;; After 4.5:\r
+;;;  (`cperl-init-faces-weak'):        use `cperl-force-face'.\r
+;;;  (`cperl-after-block-p'):  After END/BEGIN we are a block.\r
+;;;  (`cperl-mode'):           `font-lock-unfontify-region-function'\r
+;;;                            was set to a wrong function.\r
+;;;  (`cperl-comment-indent'): Commenting __END__ was not working.\r
+;;;  (`cperl-indent-for-comment'):     Likewise.\r
+;;;                            (Indenting is still misbehaving at toplevel.)\r
+\r
+;;;; After 4.5:\r
+;;;  (`cperl-unwind-to-safe'): Signature changed, unwinds end too.\r
+;;;  (`cperl-find-pods-heres'):        mark qq[]-etc sections as syntax-type=string\r
+;;;  (`cperl-fontify-syntaxically'): Unwinds start and end to go out of\r
+;;;                                 long strings (not very successful).\r
+\r
+;;;   >>>>  CPerl should be usable in write mode too now <<<<\r
+\r
+;;;  (`cperl-syntaxify-by-font-lock'): Better default - off in text-mode.\r
+;;;  (`cperl-tips'):           Updated docs.\r
+;;;  (`cperl-problems'):       Updated docs.\r
+\r
+;;;; After 4.6:\r
+;;;  (`cperl-calculate-indent'):       Did not consider `,' as continuation mark for statements.\r
+;;;  (`cperl-write-tags'):     Correct for XEmacs's `visit-tags-table-buffer'.\r
+\r
+;;;; After 4.7:\r
+;;;  (`cperl-calculate-indent'): Avoid parse-data optimization at toplevel.\r
+;;;                             Should indent correctly at toplevel too.\r
+;;;  (`cperl-tags-hier-init'): Gross hack to pretend we work (are we?).\r
+;;;  (`cperl-find-pods-heres'):        Was not processing sub protos after a comment ine.\r
+;;;                            Was treating $a++ <= 5 as a glob.\r
+\r
+;;;; After 4.8:\r
+;;;  (toplevel):               require custom unprotected => failure on 19.28.\r
+;;;  (`cperl-xemacs-p')                defined when compile too\r
+;;;  (`cperl-tags-hier-init'): Another try to work around XEmacs problems\r
+;;;                            Better progress messages.\r
+;;;  (`cperl-find-tags'):      Was writing line/pos in a wrong order,\r
+;;;                            pos off by 1 and not at beg-of-line.\r
+;;;  (`cperl-etags-snarf-tag'): New macro\r
+;;;  (`cperl-etags-goto-tag-location'): New macro\r
+;;;  (`cperl-write-tags'):     When removing old TAGS info was not\r
+;;;                            relativizing filename\r
+\r
+;;;; After 4.9:\r
+;;;  (`cperl-version'):                New variable.  New menu entry\r
+\r
+;;;; After 4.10:\r
+;;;  (`cperl-tips'):           Updated.\r
+;;;  (`cperl-non-problems'):   Updated.\r
+;;;  random:                   References to future 20.3 removed.\r
+\r
+;;;; After 4.11:\r
+;;;  (`perl-font-lock-keywords'): Would not highlight `sub foo($$);'.\r
+;;;  Docstrings:               Menu was described as `CPerl' instead of `Perl'\r
+\r
+;;;; After 4.12:\r
+;;;  (`cperl-toggle-construct-fix'): Was toggling to t instead of 1.\r
+;;;  (`cperl-ps-print-init'):  Associate `cperl-array-face', `cperl-hash-face'\r
+;;;                            remove `font-lock-emphasized-face'.\r
+;;;                            remove `font-lock-other-emphasized-face'.\r
+;;;                            remove `font-lock-reference-face'.\r
+;;;                            remove `font-lock-keyword-face'.\r
+;;;                            Use `eval-after-load'.\r
+;;;  (`cperl-init-faces'):     remove init `font-lock-other-emphasized-face'.\r
+;;;                            remove init `font-lock-emphasized-face'.\r
+;;;                            remove init `font-lock-keyword-face'.\r
+;;;  (`cperl-tips-faces'):     New variable and an entry into Mini-docs.\r
+;;;  (`cperl-indent-region'):  Do not indent whitespace lines\r
+;;;  (`cperl-indent-exp'):     Was not processing else-blocks.\r
+;;;  (`cperl-calculate-indent'): Remove another parse-data optimization\r
+;;;                             at toplevel: would indent correctly.\r
+;;;  (`cperl-get-state'):      NOP line removed.\r
+\r
+;;;; After 4.13:\r
+;;;  (`cperl-ps-print-init'):  Remove not-CPerl-related faces.\r
+;;;  (`cperl-ps-print'):       New function and menu entry.\r
+;;;  (`cperl-ps-print-face-properties'):       New configuration variable.\r
+;;;  (`cperl-invalid-face'):   New configuration variable.\r
+;;;  (`cperl-nonoverridable-face'):    New face.  Renamed from\r
+;;;                                    `font-lock-other-type-face'.\r
+;;;  (`perl-font-lock-keywords'):      Highlight trailing whitespace\r
+;;;  (`cperl-contract-levels'):        Documentation corrected.\r
+;;;  (`cperl-contract-level'): Likewise.\r
+\r
+;;;; After 4.14:\r
+;;;  (`cperl-ps-print'): `ps-print-face-extension-alist' was not in old Emaxen,\r
+;;;                            same with `ps-extend-face-list'\r
+;;;  (`cperl-ps-extend-face-list'):    New macro.\r
+\r
+;;;; After 4.15:\r
+;;;  (`cperl-init-faces'):     Interpolate `cperl-invalid-face'.\r
+;;;  (`cperl-forward-re'):     Emit a meaningful error instead of a cryptic\r
+;;;                            one for uncomplete REx near end-of-buffer.\r
+;;;  (`cperl-find-pods-heres'):        Tolerate unfinished REx at end-of-buffer.\r
+\r
+;;;; After 4.16:\r
+;;;  (`cperl-find-pods-heres'): `unwind-protect' was left commented.\r
+\r
+;;;; After 4.17:\r
+;;;  (`cperl-invalid-face'):   Change to ''underline.\r
+\r
+;;;; After 4.18:\r
+;;;  (`cperl-find-pods-heres'):        / and ? after : start a REx.\r
+;;;  (`cperl-after-expr-p'):   Skip labels when checking\r
+;;;  (`cperl-calculate-indent'): Correct for labels when calculating\r
+;;;                                    indentation of continuations.\r
+;;;                            Docstring updated.\r
+\r
+;;;; After 4.19:\r
+;;;  Minor (mostly spelling) corrections from 20.3.3 merged.\r
+\r
+;;;; After 4.20:\r
+;;;  (`cperl-tips'):           Another workaround added.  Sent to RMS for 20.4.\r
+\r
+;;;; After 4.21:\r
+;;;  (`cperl-praise'):         Mention linear-time indent.\r
+;;;  (`cperl-find-pods-heres'):        @if ? a : b was considered a REx.\r
+\r
+;;;; After 4.22:\r
+;;;  (`cperl-after-expr-p'):   Make true after __END__.\r
+;;;  (`cperl-electric-pod'):   "SYNOPSIS" was misspelled.\r
+\r
+;;;; After 4.23:\r
+;;;  (`cperl-beautify-regexp-piece'):  Was not allowing for *? after a class.\r
+;;;                                    Allow for POSIX char-classes.\r
+;;;                                    Remove trailing whitespace when\r
+;;;                                    adding new linebreak.\r
+;;;                                    Add a level counter to stop shallow.\r
+;;;                                    Indents unprocessed groups rigidly.\r
+;;;  (`cperl-beautify-regexp'):        Add an optional count argument to go that\r
+;;;                            many levels deep.\r
+;;;  (`cperl-beautify-level'): Likewise\r
+;;;  Menu:                     Add new entries to Regexp menu to do one level\r
+;;;  (`cperl-contract-level'): Was entering an infinite loop\r
+;;;  (`cperl-find-pods-heres'):        Typo (double quoting).\r
+;;;                            Was detecting < $file > as FH instead of glob.\r
+;;;                            Support for comments in RExen (except\r
+;;;                            for m#\#comment#x), governed by\r
+;;;                            `cperl-regexp-scan'.\r
+;;;  (`cperl-regexp-scan'):    New customization variable.\r
+;;;  (`cperl-forward-re'):     Improve logic of resetting syntax table.\r
+\r
+;;;; After 4.23 and: After 4.24:\r
+;;;  (`cperl-contract-levels'):        Restore position.\r
+;;;  (`cperl-beautify-level'): Likewise.\r
+;;;  (`cperl-beautify-regexp'):        Likewise.\r
+;;;  (`cperl-commentify'):     Rudimental support for length=1 runs\r
+;;;  (`cperl-find-pods-heres'):        Process 1-char long REx comments too /a#/x\r
+;;;                            Processes REx-comments in #-delimited RExen.\r
+;;;                            MAJOR BUG CORRECTED: after a misparse\r
+;;;                              a body of a subroutine could be corrupted!!!\r
+;;;                              One might need to reeval the function body\r
+;;;                              to fix things.  (A similar bug was\r
+;;;                              present in `cperl-indent-region' eons ago.)\r
+;;; To reproduce:\r
+;;   (defun foo () (let ((a '(t))) (insert (format "%s" a)) (setcar a 'BUG) t))\r
+;;   (foo)\r
+;;   (foo)\r
+;;; C-x C-e the above three lines (at end-of-line).  First evaluation\r
+;;; of `foo' inserts (t), second one inserts (BUG) ?!\r
+;;;\r
+;;; In CPerl it was triggered by inserting then deleting `/' at start of\r
+;;;      /  a (?# asdf  {[(}asdf )ef,/;\r
+\r
+;;;; After 4.25:\r
+;;; (`cperl-commentify'):      Was recognizing length=2 "strings" as length=1.\r
+;;; (`imenu-example--create-perl-index'):\r
+;;;                            Was not enforcing syntaxification-to-the-end.\r
+;;; (`cperl-invert-if-unless'):        Allow `for', `foreach'.\r
+;;; (`cperl-find-pods-heres'): Quote `cperl-nonoverridable-face'.\r
+;;;                            Mark qw(), m()x as indentable.\r
+;;; (`cperl-init-faces'):      Highlight `sysopen' too.\r
+;;;                            Highlight $var in `for my $var' too.\r
+;;; (`cperl-invert-if-unless'):        Was leaving whitespace at end.\r
+;;; (`cperl-linefeed'):                Was splitting $var{$foo} if point after `{'.\r
+;;; (`cperl-calculate-indent'): Remove old commented out code.\r
+;;;                            Support (primitive) indentation of qw(), m()x.\r
+\r
+\r
+;;;; After 4.26:\r
+;;; (`cperl-problems'):                Mention `fill-paragraph' on comment. \"" and\r
+;;;                            q [] with intervening newlines.\r
+;;; (`cperl-autoindent-on-semi'):      New customization variable.\r
+;;; (`cperl-electric-semi'):   Use `cperl-autoindent-on-semi'.\r
+;;; (`cperl-tips'):            Mention how to make CPerl the default mode.\r
+;;; (`cperl-mode'):            Support `outline-minor-mode'\r
+;;;                            (Thanks to Mark A. Hershberger).\r
+;;; (`cperl-outline-level'):   New function.\r
+;;; (`cperl-highlight-variables-indiscriminately'):    New customization var.\r
+;;; (`cperl-init-faces'):      Use `cperl-highlight-variables-indiscriminately'.\r
+;;;                            (Thanks to Sean Kamath <kamath@pogo.wv.tek.com>).\r
+;;; (`cperl-after-block-p'):   Support CHECK and INIT.\r
+;;; (`cperl-init-faces'):      Likewise and "our".\r
+;;;                            (Thanks to Doug MacEachern <dougm@covalent.net>).\r
+;;; (`cperl-short-docs'):      Likewise and "our".\r
+\r
+\r
+;;;; After 4.27:\r
+;;; (`cperl-find-pods-heres'): Recognize \"" as a string.\r
+;;;                            Mark whitespace and comments between q and []\r
+;;;                              as `syntax-type' => `prestring'.\r
+;;;                            Allow whitespace between << and "FOO".\r
+;;; (`cperl-problems'):                Remove \"" and q [] with intervening newlines.\r
+;;;                            Mention multiple <<EOF as unsupported.\r
+;;; (`cperl-highlight-variables-indiscriminately'):    Doc misprint fixed.\r
+;;; (`cperl-indent-parens-as-block'):  New configuration variable.\r
+;;; (`cperl-calculate-indent'):        Merge cases of indenting non-BLOCK groups.\r
+;;;                            Use `cperl-indent-parens-as-block'.\r
+;;; (`cperl-find-pods-heres'): Test for =cut without empty line instead of\r
+;;;                            complaining about no =cut.\r
+;;; (`cperl-electric-pod'):    Change the REx for POD from "\n\n=" to "^\n=".\r
+;;; (`cperl-find-pods-heres'): Likewise.\r
+;;; (`cperl-electric-pod'):    Change `forward-sexp' to `forward-word':\r
+;;;                            POD could've been marked as comment already.\r
+;;; (`cperl-unwind-to-safe'):  Unwind before start of POD too.\r
+\r
+;;;; After 4.28:\r
+;;; (`cperl-forward-re'):      Throw an error at proper moment REx unfinished.\r
+\r
+;;;; After 4.29:\r
+;;; (`x-color-defined-p'):     Make an extra case to peacify the warning.\r
+;;; Toplevel:                  `defvar' to peacify the warnings.\r
+;;; (`cperl-find-pods-heres'): Could access `font-lock-comment-face' in -nw.\r
+;;;;                           No -nw-compile time warnings now.\r
+;;; (`cperl-find-tags'):       TAGS file had too short substring-to-search.\r
+;;;                            Be less verbose in non-interactive mode\r
+;;; (`imenu-example--create-perl-index'):      Set index-marker after name\r
+;;; (`cperl-outline-regexp'):  New variable.\r
+;;; (`cperl-outline-level'):   Made compatible with `cperl-outline-regexp'.\r
+;;; (`cperl-mode'):            Made use `cperl-outline-regexp'.\r
+\r
+;;;; After 4.30:\r
+;;; (`cperl-find-pods-heres'): =cut the last thing, no blank line, was error.\r
+;;; (`cperl-outline-level'):   Make start-of-file same level as `package'.\r
+\r
+;;;; After 4.31:\r
+;;; (`cperl-electric-pod'):    `head1' and `over' electric only if empty.\r
+;;; (`cperl-unreadable-ok'):   New variable.\r
+;;; (`cperl-find-tags'):       Use `cperl-unreadable-ok', do not fail\r
+;;;                            on an unreadable file\r
+;;; (`cperl-write-tags'):      Use `cperl-unreadable-ok', do not fail\r
+;;;                            on an unreadable directory\r
+\r
+;;;; After 4.32:\r
+;;;  Syncronized with v1.60 from Emacs 21.3.\r
+;;;  Mostly docstring and formatting changes, and:\r
+\r
+;;;  (`cperl-noscan-files-regexp'): Do not scan CVS subdirs\r
+;;;  (`cperl-problems'):       Note that newer XEmacsen may syntaxify too\r
+;;;  (`imenu-example--create-perl-index'):\r
+;;;                            Renamed to `cperl-imenu--create-perl-index'\r
+;;;  (`cperl-mode'):           Replace `make-variable-buffer-local' by `make-local-variable'\r
+;;;  (`cperl-setup-tmp-buf'):  Likewise\r
+;;;  (`cperl-fix-line-spacing'): Fix a misprint of "t" for "\t"\r
+;;;  (`cperl-next-bad-style'):  Fix misprints in character literals\r
+\r
+;;;; After 4.33:\r
+;;;  (`cperl-font-lock-keywords'): +etc: Aliased to perl-font-lock-keywords.\r
+\r
+;;;; After 4.34:\r
+;;;  Further updates of whitespace and spelling w.r.t. RMS version.\r
+;;;  (`cperl-font-lock-keywords'): +etc: Avoid warnings when aliasing.\r
+;;;  (`cperl-mode'):           Use `normal-auto-fill-function' if present.\r
+;;;  (`cperl-use-major-mode'): New variable\r
+;;;  (`cperl-can-font-lock'):  New variable; replaces `window-system'\r
+;;;  (`cperl-tags-hier-init'): use `display-popup-menus-p' (if present)\r
+;;;                            to choose `x-popup-menu' vs `tmm-prompt'\r
+\r
+;;;; 4.35 has the following differences from version 1.40+ of RMS Emacs:\r
+\r
+;;; New variables `cperl-use-major-mode', `cperl-can-font-lock';\r
+;;; `cperl-use-major-mode' is (effectively) 'cperl-mode in RMS.\r
+;;; `cperl-under-as-char'  is nil in RMS.\r
+;;; Minor differences in docstrings, and `cperl-non-problems'.\r
+;;; Backward compatibility addressed: (`); (function (lambda ...)); font-lock;\r
+;;; (:italic t bold t) vs (:slant italic :weight bold) in faces;\r
+;;; `normal-auto-fill-function'.\r
+;;; RMS version has wrong logic in `cperl-calculate-indent': $a = { } is\r
+;;; wrongly indented if the closing brace is on a separate line.\r
+;;; Different choice of ordering if's for is-x-REx and (eq (char-after b) ?\#)\r
+;;; in `cperl-find-pods-heres'. [Cosmetic]\r
+\r
+;;;; After 4.35:\r
+;;;  (`cperl-find-pods-heres'):        If no end of HERE-doc found, mark to the end\r
+;;;                            of buffer.  This enables recognition of end\r
+;;;                            of HERE-doc "as one types".\r
+;;;                            Require "\n" after trailing tag of HERE-doc.\r
+;;;                            \( made non-quoting outside of string/comment\r
+;;;                            (gdj-contributed).\r
+;;;                            Likewise for \$.\r
+;;;                            Remove `here-doc-group' text property at start\r
+;;;                            (makes this property reliable).\r
+;;;                            Text property `first-format-line' ==> t.\r
+;;;                            Do not recognize $opt_s and $opt::s as s///.\r
+;;;  (`cperl-perldoc'):                Use case-sensitive search (contributed).\r
+;;;  (`cperl-fix-line-spacing'): Allow "_" in $vars of foreach etc. when\r
+;;;                            underscore isn't a word char (gdj-contributed).\r
+;;;  (`defun-prompt-regexp'):  Allow prototypes.\r
+;;;  (`cperl-vc-header-alist'):        Extract numeric version from the Id.\r
+;;;  Toplevel:                 Put toggle-autohelp into the mode menu.\r
+;;;                            Better docs for toggle/set/unset autohelp.\r
+;;;  (`cperl-electric-backspace-untabify'): New customization variable\r
+;;;  (`cperl-after-expr-p'):   Works after here-docs, formats, and PODs too\r
+;;;                            (affects many electric constructs).\r
+;;;  (`cperl-calculate-indent'): Takes into account `first-format-line' ==>\r
+;;;                            works after format.\r
+;;;  (`cperl-short-docs'):     Make it work with ... too.\r
+;;;                            "array context" ==> "list context"\r
+;;;  (`cperl-electric-keyword'): make $if (etc: "$@%&*") non-electric\r
+;;;                            '(' after keyword would insert a doubled paren\r
+;;;  (`cperl-electric-paren'): documented affected by `cperl-electric-parens'\r
+;;;  (`cperl-electric-rparen'):        Likewise\r
+;;;  (`cperl-build-manpage'):  New function by Nick Roberts\r
+;;;  (`cperl-perldoc'):                Make it work in XEmacs too\r
+\r
+;;;; After 4.36:\r
+;;;  (`cperl-find-pods-heres'):        Recognize s => 1 and {s} (as a key or varname),\r
+;;;                            { s:: } and { s::bar::baz } as varnames.\r
+;;;  (`cperl-after-expr-p'):   Updates syntaxification before checks\r
+;;;  (`cperl-calculate-indent'): Likewise\r
+;;;                            Fix wrong indent of blocks starting with POD\r
+;;;  (`cperl-after-block-p'):  Optional argument for checking for a pre-block\r
+;;;                            Recognize `continue' blocks too.\r
+;;;  (`cperl-electric-brace'): use `cperl-after-block-p' for detection;\r
+;;;                            Now works for else/continue/sub blocks\r
+;;;  (`cperl-short-docs'):     Minor edits; make messages fit 80-column screen\r
+\r
+;;; Code:\r
+\r
+\f\r
+(if (fboundp 'eval-when-compile)\r
+    (eval-when-compile\r
+      (condition-case nil\r
+         (require 'custom)\r
+       (error nil))\r
+      (condition-case nil\r
+         (require 'man)\r
+       (error nil))\r
+      (defconst cperl-xemacs-p (string-match "XEmacs\\|Lucid" emacs-version))\r
+      (defvar cperl-can-font-lock\r
+       (or cperl-xemacs-p\r
+           (and (boundp 'emacs-major-version)\r
+                (or window-system\r
+                    (> emacs-major-version 20)))))\r
+      (if cperl-can-font-lock\r
+         (require 'font-lock))\r
+      (defvar msb-menu-cond)\r
+      (defvar gud-perldb-history)\r
+      (defvar font-lock-background-mode) ; not in Emacs\r
+      (defvar font-lock-display-type)  ; ditto\r
+      (or (fboundp 'defgroup)\r
+         (defmacro defgroup (name val doc &rest arr)\r
+           nil))\r
+      (or (fboundp 'custom-declare-variable)\r
+         (defmacro defcustom (name val doc &rest arr)\r
+           (` (defvar (, name) (, val) (, doc)))))\r
+      (or (and (fboundp 'custom-declare-variable)\r
+              (string< "19.31" emacs-version)) ;  Checked with 19.30: defface does not work\r
+         (defmacro defface (&rest arr)\r
+           nil))\r
+      ;; Avoid warning (tmp definitions)\r
+      (or (fboundp 'x-color-defined-p)\r
+         (defmacro x-color-defined-p (col)\r
+           (cond ((fboundp 'color-defined-p) (` (color-defined-p (, col))))\r
+                 ;; XEmacs >= 19.12\r
+                 ((fboundp 'valid-color-name-p) (` (valid-color-name-p (, col))))\r
+                 ;; XEmacs 19.11\r
+                 ((fboundp 'x-valid-color-name-p) (` (x-valid-color-name-p (, col))))\r
+                 (t '(error "Cannot implement color-defined-p")))))\r
+      (defmacro cperl-is-face (arg)    ; Takes quoted arg\r
+       (cond ((fboundp 'find-face)\r
+              (` (find-face (, arg))))\r
+             (;;(and (fboundp 'face-list)\r
+              ;;       (face-list))\r
+              (fboundp 'face-list)\r
+              (` (member (, arg) (and (fboundp 'face-list)\r
+                                      (face-list)))))\r
+             (t\r
+              (` (boundp (, arg))))))\r
+      (defmacro cperl-make-face (arg descr) ; Takes unquoted arg\r
+       (cond ((fboundp 'make-face)\r
+              (` (make-face (quote (, arg)))))\r
+             (t\r
+              (` (defvar (, arg) (quote (, arg)) (, descr))))))\r
+      (defmacro cperl-force-face (arg descr) ; Takes unquoted arg\r
+       (` (progn\r
+            (or (cperl-is-face (quote (, arg)))\r
+                (cperl-make-face (, arg) (, descr)))\r
+            (or (boundp (quote (, arg))) ; We use unquoted variants too\r
+                (defvar (, arg) (quote (, arg)) (, descr))))))\r
+      (if cperl-xemacs-p\r
+         (defmacro cperl-etags-snarf-tag (file line)\r
+           (` (progn\r
+                (beginning-of-line 2)\r
+                (list (, file) (, line)))))\r
+       (defmacro cperl-etags-snarf-tag (file line)\r
+         (` (etags-snarf-tag))))\r
+      (if cperl-xemacs-p\r
+         (defmacro cperl-etags-goto-tag-location (elt)\r
+           (`;;(progn\r
+            ;; (switch-to-buffer (get-file-buffer (elt (, elt) 0)))\r
+            ;; (set-buffer (get-file-buffer (elt (, elt) 0)))\r
+            ;; Probably will not work due to some save-excursion???\r
+            ;; Or save-file-position?\r
+            ;; (message "Did I get to line %s?" (elt (, elt) 1))\r
+            (goto-line (string-to-int (elt (, elt) 1)))))\r
+       ;;)\r
+       (defmacro cperl-etags-goto-tag-location (elt)\r
+         (` (etags-goto-tag-location (, elt)))))))\r
+\r
+(defconst cperl-xemacs-p (string-match "XEmacs\\|Lucid" emacs-version))\r
+\r
+(defvar cperl-can-font-lock\r
+  (or cperl-xemacs-p\r
+      (and (boundp 'emacs-major-version)\r
+          (or window-system\r
+              (> emacs-major-version 20)))))\r
+\r
+(condition-case nil\r
+    (require 'custom)\r
+  (error nil))                         ; Already fixed by eval-when-compile\r
+\r
+(defun cperl-choose-color (&rest list)\r
+  (let (answer)\r
+    (while list\r
+      (or answer\r
+         (if (or (x-color-defined-p (car list))\r
+                 (null (cdr list)))\r
+             (setq answer (car list))))\r
+      (setq list (cdr list)))\r
+    answer))\r
+\r
+\f\r
+(defgroup cperl nil\r
+  "Major mode for editing Perl code."\r
+  :prefix "cperl-"\r
+  :group 'languages)\r
+\r
+(defgroup cperl-indentation-details nil\r
+  "Indentation."\r
+  :prefix "cperl-"\r
+  :group 'cperl)\r
+\r
+(defgroup cperl-affected-by-hairy nil\r
+  "Variables affected by `cperl-hairy'."\r
+  :prefix "cperl-"\r
+  :group 'cperl)\r
+\r
+(defgroup cperl-autoinsert-details nil\r
+  "Auto-insert tuneup."\r
+  :prefix "cperl-"\r
+  :group 'cperl)\r
+\r
+(defgroup cperl-faces nil\r
+  "Fontification colors."\r
+  :prefix "cperl-"\r
+  :group 'cperl)\r
+\r
+(defgroup cperl-speed nil\r
+  "Speed vs. validity tuneup."\r
+  :prefix "cperl-"\r
+  :group 'cperl)\r
+\r
+(defgroup cperl-help-system nil\r
+  "Help system tuneup."\r
+  :prefix "cperl-"\r
+  :group 'cperl)\r
+\r
+\f\r
+(defcustom cperl-extra-newline-before-brace nil\r
+  "*Non-nil means that if, elsif, while, until, else, for, foreach\r
+and do constructs look like:\r
+\r
+       if ()\r
+       {\r
+       }\r
+\r
+instead of:\r
+\r
+       if () {\r
+       }"\r
+  :type 'boolean\r
+  :group 'cperl-autoinsert-details)\r
+\r
+(defcustom cperl-extra-newline-before-brace-multiline\r
+  cperl-extra-newline-before-brace\r
+  "*Non-nil means the same as `cperl-extra-newline-before-brace', but\r
+for constructs with multiline if/unless/while/until/for/foreach condition."\r
+  :type 'boolean\r
+  :group 'cperl-autoinsert-details)\r
+\r
+(defcustom cperl-indent-level 2\r
+  "*Indentation of CPerl statements with respect to containing block."\r
+  :type 'integer\r
+  :group 'cperl-indentation-details)\r
+\r
+(defcustom cperl-lineup-step nil\r
+  "*`cperl-lineup' will always lineup at multiple of this number.\r
+If nil, the value of `cperl-indent-level' will be used."\r
+  :type '(choice (const nil) integer)\r
+  :group 'cperl-indentation-details)\r
+\r
+(defcustom cperl-brace-imaginary-offset 0\r
+  "*Imagined indentation of a Perl open brace that actually follows a statement.\r
+An open brace following other text is treated as if it were this far\r
+to the right of the start of its line."\r
+  :type 'integer\r
+  :group 'cperl-indentation-details)\r
+\r
+(defcustom cperl-brace-offset 0\r
+  "*Extra indentation for braces, compared with other text in same context."\r
+  :type 'integer\r
+  :group 'cperl-indentation-details)\r
+(defcustom cperl-label-offset -2\r
+  "*Offset of CPerl label lines relative to usual indentation."\r
+  :type 'integer\r
+  :group 'cperl-indentation-details)\r
+(defcustom cperl-min-label-indent 1\r
+  "*Minimal offset of CPerl label lines."\r
+  :type 'integer\r
+  :group 'cperl-indentation-details)\r
+(defcustom cperl-continued-statement-offset 2\r
+  "*Extra indent for lines not starting new statements."\r
+  :type 'integer\r
+  :group 'cperl-indentation-details)\r
+(defcustom cperl-continued-brace-offset 0\r
+  "*Extra indent for substatements that start with open-braces.\r
+This is in addition to cperl-continued-statement-offset."\r
+  :type 'integer\r
+  :group 'cperl-indentation-details)\r
+(defcustom cperl-close-paren-offset -1\r
+  "*Extra indent for substatements that start with close-parenthesis."\r
+  :type 'integer\r
+  :group 'cperl-indentation-details)\r
+\r
+(defcustom cperl-auto-newline nil\r
+  "*Non-nil means automatically newline before and after braces,\r
+and after colons and semicolons, inserted in CPerl code.  The following\r
+\\[cperl-electric-backspace] will remove the inserted whitespace.\r
+Insertion after colons requires both this variable and\r
+`cperl-auto-newline-after-colon' set."\r
+  :type 'boolean\r
+  :group 'cperl-autoinsert-details)\r
+\r
+(defcustom cperl-autoindent-on-semi nil\r
+  "*Non-nil means automatically indent after insertion of (semi)colon.\r
+Active if `cperl-auto-newline' is false."\r
+  :type 'boolean\r
+  :group 'cperl-autoinsert-details)\r
+\r
+(defcustom cperl-auto-newline-after-colon nil\r
+  "*Non-nil means automatically newline even after colons.\r
+Subject to `cperl-auto-newline' setting."\r
+  :type 'boolean\r
+  :group 'cperl-autoinsert-details)\r
+\r
+(defcustom cperl-tab-always-indent t\r
+  "*Non-nil means TAB in CPerl mode should always reindent the current line,\r
+regardless of where in the line point is when the TAB command is used."\r
+  :type 'boolean\r
+  :group 'cperl-indentation-details)\r
+\r
+(defcustom cperl-font-lock nil\r
+  "*Non-nil (and non-null) means CPerl buffers will use `font-lock-mode'.\r
+Can be overwritten by `cperl-hairy' if nil."\r
+  :type '(choice (const null) boolean)\r
+  :group 'cperl-affected-by-hairy)\r
+\r
+(defcustom cperl-electric-lbrace-space nil\r
+  "*Non-nil (and non-null) means { after $ should be preceded by ` '.\r
+Can be overwritten by `cperl-hairy' if nil."\r
+  :type '(choice (const null) boolean)\r
+  :group 'cperl-affected-by-hairy)\r
+\r
+(defcustom cperl-electric-parens-string "({[]})<"\r
+  "*String of parentheses that should be electric in CPerl.\r
+Closing ones are electric only if the region is highlighted."\r
+  :type 'string\r
+  :group 'cperl-affected-by-hairy)\r
+\r
+(defcustom cperl-electric-parens nil\r
+  "*Non-nil (and non-null) means parentheses should be electric in CPerl.\r
+Can be overwritten by `cperl-hairy' if nil."\r
+  :type '(choice (const null) boolean)\r
+  :group 'cperl-affected-by-hairy)\r
+\r
+(defvar zmacs-regions)                 ; Avoid warning\r
+\r
+(defcustom cperl-electric-parens-mark\r
+  (and window-system\r
+       (or (and (boundp 'transient-mark-mode) ; For Emacs\r
+               transient-mark-mode)\r
+          (and (boundp 'zmacs-regions) ; For XEmacs\r
+               zmacs-regions)))\r
+  "*Not-nil means that electric parens look for active mark.\r
+Default is yes if there is visual feedback on mark."\r
+  :type 'boolean\r
+  :group 'cperl-autoinsert-details)\r
+\r
+(defcustom cperl-electric-linefeed nil\r
+  "*If true, LFD should be hairy in CPerl, otherwise C-c LFD is hairy.\r
+In any case these two mean plain and hairy linefeeds together.\r
+Can be overwritten by `cperl-hairy' if nil."\r
+  :type '(choice (const null) boolean)\r
+  :group 'cperl-affected-by-hairy)\r
+\r
+(defcustom cperl-electric-keywords nil\r
+  "*Not-nil (and non-null) means keywords are electric in CPerl.\r
+Can be overwritten by `cperl-hairy' if nil."\r
+  :type '(choice (const null) boolean)\r
+  :group 'cperl-affected-by-hairy)\r
+\r
+(defcustom cperl-electric-backspace-untabify t\r
+  "*Not-nil means electric-backspace will untabify in CPerl."\r
+  :type 'boolean\r
+  :group 'cperl-autoinsert-details)\r
+\r
+(defcustom cperl-hairy nil\r
+  "*Not-nil means most of the bells and whistles are enabled in CPerl.\r
+Affects: `cperl-font-lock', `cperl-electric-lbrace-space',\r
+`cperl-electric-parens', `cperl-electric-linefeed', `cperl-electric-keywords',\r
+`cperl-info-on-command-no-prompt', `cperl-clobber-lisp-bindings',\r
+`cperl-lazy-help-time'."\r
+  :type 'boolean\r
+  :group 'cperl-affected-by-hairy)\r
+\r
+(defcustom cperl-comment-column 32\r
+  "*Column to put comments in CPerl (use \\[cperl-indent] to lineup with code)."\r
+  :type 'integer\r
+  :group 'cperl-indentation-details)\r
+\r
+(defcustom cperl-vc-header-alist '((SCCS "($sccs) = ('%W\%' =~ /(\\d+(\\.\\d+)+)/) ;")\r
+                                  (RCS "($rcs) = (' $Id\$ ' =~ /(\\d+(\\.\\d+)+)/) ;"))\r
+  "*What to use as `vc-header-alist' in CPerl."\r
+  :type '(repeat (list symbol string))\r
+  :group 'cperl)\r
+\r
+(defcustom cperl-clobber-mode-lists\r
+  (not\r
+   (and\r
+    (boundp 'interpreter-mode-alist)\r
+    (assoc "miniperl" interpreter-mode-alist)\r
+    (assoc "\\.\\([pP][Llm]\\|al\\)$" auto-mode-alist)))\r
+  "*Whether to install us into `interpreter-' and `extension' mode lists."\r
+  :type 'boolean\r
+  :group 'cperl)\r
+\r
+(defcustom cperl-info-on-command-no-prompt nil\r
+  "*Not-nil (and non-null) means not to prompt on C-h f.\r
+The opposite behaviour is always available if prefixed with C-c.\r
+Can be overwritten by `cperl-hairy' if nil."\r
+  :type '(choice (const null) boolean)\r
+  :group 'cperl-affected-by-hairy)\r
+\r
+(defcustom cperl-clobber-lisp-bindings nil\r
+  "*Not-nil (and non-null) means not overwrite C-h f.\r
+The function is available on \\[cperl-info-on-command], \\[cperl-get-help].\r
+Can be overwritten by `cperl-hairy' if nil."\r
+  :type '(choice (const null) boolean)\r
+  :group 'cperl-affected-by-hairy)\r
+\r
+(defcustom cperl-lazy-help-time nil\r
+  "*Not-nil (and non-null) means to show lazy help after given idle time.\r
+Can be overwritten by `cperl-hairy' to be 5 sec if nil."\r
+  :type '(choice (const null) (const nil) integer)\r
+  :group 'cperl-affected-by-hairy)\r
+\r
+(defcustom cperl-pod-face 'font-lock-comment-face\r
+  "*The result of evaluation of this expression is used for POD highlighting."\r
+  :type 'face\r
+  :group 'cperl-faces)\r
+\r
+(defcustom cperl-pod-head-face 'font-lock-variable-name-face\r
+  "*The result of evaluation of this expression is used for POD highlighting.\r
+Font for POD headers."\r
+  :type 'face\r
+  :group 'cperl-faces)\r
+\r
+(defcustom cperl-here-face 'font-lock-string-face\r
+  "*The result of evaluation of this expression is used for here-docs highlighting."\r
+  :type 'face\r
+  :group 'cperl-faces)\r
+\r
+(defcustom cperl-invalid-face ''underline ; later evaluated by `font-lock'\r
+  "*The result of evaluation of this expression highlights trailing whitespace."\r
+  :type 'face\r
+  :group 'cperl-faces)\r
+\r
+(defcustom cperl-pod-here-fontify '(featurep 'font-lock)\r
+  "*Not-nil after evaluation means to highlight POD and here-docs sections."\r
+  :type 'boolean\r
+  :group 'cperl-faces)\r
+\r
+(defcustom cperl-fontify-m-as-s t\r
+  "*Not-nil means highlight 1arg regular expressions operators same as 2arg."\r
+  :type 'boolean\r
+  :group 'cperl-faces)\r
+\r
+(defcustom cperl-highlight-variables-indiscriminately nil\r
+  "*Non-nil means perform additional highlighting on variables.\r
+Currently only changes how scalar variables are highlighted.\r
+Note that that variable is only read at initialization time for\r
+the variable `perl-font-lock-keywords-2', so changing it after you've\r
+entered CPerl mode the first time will have no effect."\r
+  :type 'boolean\r
+  :group 'cperl)\r
+\r
+(defcustom cperl-pod-here-scan t\r
+  "*Not-nil means look for POD and here-docs sections during startup.\r
+You can always make lookup from menu or using \\[cperl-find-pods-heres]."\r
+  :type 'boolean\r
+  :group 'cperl-speed)\r
+\r
+(defcustom cperl-regexp-scan t\r
+  "*Not-nil means make marking of regular expression more thorough.\r
+Effective only with `cperl-pod-here-scan'.  Not implemented yet."\r
+  :type 'boolean\r
+  :group 'cperl-speed)\r
+\r
+(defcustom cperl-imenu-addback nil\r
+  "*Not-nil means add backreferences to generated `imenu's.\r
+May require patched `imenu' and `imenu-go'.  Obsolete."\r
+  :type 'boolean\r
+  :group 'cperl-help-system)\r
+\r
+(defcustom cperl-max-help-size 66\r
+  "*Non-nil means shrink-wrapping of info-buffer allowed up to these percents."\r
+  :type '(choice integer (const nil))\r
+  :group 'cperl-help-system)\r
+\r
+(defcustom cperl-shrink-wrap-info-frame t\r
+  "*Non-nil means shrink-wrapping of info-buffer-frame allowed."\r
+  :type 'boolean\r
+  :group 'cperl-help-system)\r
+\r
+(defcustom cperl-info-page "perl"\r
+  "*Name of the info page containing perl docs.\r
+Older version of this page was called `perl5', newer `perl'."\r
+  :type 'string\r
+  :group 'cperl-help-system)\r
+\r
+(defcustom cperl-use-syntax-table-text-property\r
+  (boundp 'parse-sexp-lookup-properties)\r
+  "*Non-nil means CPerl sets up and uses `syntax-table' text property."\r
+  :type 'boolean\r
+  :group 'cperl-speed)\r
+\r
+(defcustom cperl-use-syntax-table-text-property-for-tags\r
+  cperl-use-syntax-table-text-property\r
+  "*Non-nil means: set up and use `syntax-table' text property generating TAGS."\r
+  :type 'boolean\r
+  :group 'cperl-speed)\r
+\r
+(defcustom cperl-scan-files-regexp "\\.\\([pP][Llm]\\|xs\\)$"\r
+  "*Regexp to match files to scan when generating TAGS."\r
+  :type 'regexp\r
+  :group 'cperl)\r
+\r
+(defcustom cperl-noscan-files-regexp\r
+  "/\\(\\.\\.?\\|SCCS\\|RCS\\|CVS\\|blib\\)$"\r
+  "*Regexp to match files/dirs to skip when generating TAGS."\r
+  :type 'regexp\r
+  :group 'cperl)\r
+\r
+(defcustom cperl-regexp-indent-step nil\r
+  "*Indentation used when beautifying regexps.\r
+If nil, the value of `cperl-indent-level' will be used."\r
+  :type '(choice integer (const nil))\r
+  :group 'cperl-indentation-details)\r
+\r
+(defcustom cperl-indent-left-aligned-comments t\r
+  "*Non-nil means that the comment starting in leftmost column should indent."\r
+  :type 'boolean\r
+  :group 'cperl-indentation-details)\r
+\r
+(defcustom cperl-under-as-char t\r
+  "*Non-nil means that the _ (underline) should be treated as word char."\r
+  :type 'boolean\r
+  :group 'cperl)\r
+\r
+(defcustom cperl-extra-perl-args ""\r
+  "*Extra arguments to use when starting Perl.\r
+Currently used with `cperl-check-syntax' only."\r
+  :type 'string\r
+  :group 'cperl)\r
+\r
+(defcustom cperl-message-electric-keyword t\r
+  "*Non-nil means that the `cperl-electric-keyword' prints a help message."\r
+  :type 'boolean\r
+  :group 'cperl-help-system)\r
+\r
+(defcustom cperl-indent-region-fix-constructs 1\r
+  "*Amount of space to insert between `}' and `else' or `elsif'\r
+in `cperl-indent-region'.  Set to nil to leave as is.  Values other\r
+than 1 and nil will probably not work."\r
+  :type '(choice (const nil) (const 1))\r
+  :group 'cperl-indentation-details)\r
+\r
+(defcustom cperl-break-one-line-blocks-when-indent t\r
+  "*Non-nil means that one-line if/unless/while/until/for/foreach BLOCKs\r
+need to be reformatted into multiline ones when indenting a region."\r
+  :type 'boolean\r
+  :group 'cperl-indentation-details)\r
+\r
+(defcustom cperl-fix-hanging-brace-when-indent t\r
+  "*Non-nil means that BLOCK-end `}' may be put on a separate line\r
+when indenting a region.\r
+Braces followed by else/elsif/while/until are excepted."\r
+  :type 'boolean\r
+  :group 'cperl-indentation-details)\r
+\r
+(defcustom cperl-merge-trailing-else t\r
+  "*Non-nil means that BLOCK-end `}' followed by else/elsif/continue\r
+may be merged to be on the same line when indenting a region."\r
+  :type 'boolean\r
+  :group 'cperl-indentation-details)\r
+\r
+(defcustom cperl-indent-parens-as-block nil\r
+  "*Non-nil means that non-block ()-, {}- and []-groups are indented as blocks,\r
+but for trailing \",\" inside the group, which won't increase indentation.\r
+One should tune up `cperl-close-paren-offset' as well."\r
+  :type 'boolean\r
+  :group 'cperl-indentation-details)\r
+\r
+(defcustom cperl-syntaxify-by-font-lock\r
+  (and cperl-can-font-lock\r
+       (boundp 'parse-sexp-lookup-properties))\r
+  "*Non-nil means that CPerl uses `font-lock's routines for syntaxification."\r
+  :type '(choice (const message) boolean)\r
+  :group 'cperl-speed)\r
+\r
+(defcustom cperl-syntaxify-unwind\r
+  t\r
+  "*Non-nil means that CPerl unwinds to a start of a long construction\r
+when syntaxifying a chunk of buffer."\r
+  :type 'boolean\r
+  :group 'cperl-speed)\r
+\r
+(defcustom cperl-ps-print-face-properties\r
+  '((font-lock-keyword-face            nil nil         bold shadow)\r
+    (font-lock-variable-name-face      nil nil         bold)\r
+    (font-lock-function-name-face      nil nil         bold italic box)\r
+    (font-lock-constant-face           nil "LightGray" bold)\r
+    (cperl-array-face                  nil "LightGray" bold underline)\r
+    (cperl-hash-face                   nil "LightGray" bold italic underline)\r
+    (font-lock-comment-face            nil "LightGray" italic)\r
+    (font-lock-string-face             nil nil         italic underline)\r
+    (cperl-nonoverridable-face         nil nil         italic underline)\r
+    (font-lock-type-face               nil nil         underline)\r
+    (underline                         nil "LightGray" strikeout))\r
+  "List given as an argument to `ps-extend-face-list' in `cperl-ps-print'."\r
+  :type '(repeat (cons symbol\r
+                      (cons (choice (const nil) string)\r
+                            (cons (choice (const nil) string)\r
+                                  (repeat symbol)))))\r
+  :group 'cperl-faces)\r
+\r
+(if cperl-can-font-lock\r
+    (progn\r
+      (defvar cperl-dark-background\r
+       (cperl-choose-color "navy" "os2blue" "darkgreen"))\r
+      (defvar cperl-dark-foreground\r
+       (cperl-choose-color "orchid1" "orange"))\r
+\r
+      (defface cperl-nonoverridable-face\r
+       (` ((((class grayscale) (background light))\r
+            (:background "Gray90" :italic t :underline t))\r
+           (((class grayscale) (background dark))\r
+            (:foreground "Gray80" :italic t :underline t :bold t))\r
+           (((class color) (background light))\r
+            (:foreground "chartreuse3"))\r
+           (((class color) (background dark))\r
+            (:foreground (, cperl-dark-foreground)))\r
+           (t (:bold t :underline t))))\r
+       "Font Lock mode face used to highlight array names."\r
+       :group 'cperl-faces)\r
+\r
+      (defface cperl-array-face\r
+       (` ((((class grayscale) (background light))\r
+            (:background "Gray90" :bold t))\r
+           (((class grayscale) (background dark))\r
+            (:foreground "Gray80" :bold t))\r
+           (((class color) (background light))\r
+            (:foreground "Blue" :background "lightyellow2" :bold t))\r
+           (((class color) (background dark))\r
+            (:foreground "yellow" :background (, cperl-dark-background) :bold t))\r
+           (t (:bold t))))\r
+       "Font Lock mode face used to highlight array names."\r
+       :group 'cperl-faces)\r
+\r
+      (defface cperl-hash-face\r
+       (` ((((class grayscale) (background light))\r
+            (:background "Gray90" :bold t :italic t))\r
+           (((class grayscale) (background dark))\r
+            (:foreground "Gray80" :bold t :italic t))\r
+           (((class color) (background light))\r
+            (:foreground "Red" :background "lightyellow2" :bold t :italic t))\r
+           (((class color) (background dark))\r
+            (:foreground "Red" :background (, cperl-dark-background) :bold t :italic t))\r
+           (t (:bold t :italic t))))\r
+       "Font Lock mode face used to highlight hash names."\r
+       :group 'cperl-faces)))\r
+\r
+\f\r
+\r
+;;; Short extra-docs.\r
+\r
+(defvar cperl-tips 'please-ignore-this-line\r
+  "Get maybe newer version of this package from\r
+  ftp://ftp.math.ohio-state.edu/pub/users/ilya/emacs\r
+and/or\r
+  ftp://ftp.math.ohio-state.edu/pub/users/ilya/perl\r
+Subdirectory `cperl-mode' may contain yet newer development releases and/or\r
+patches to related files.\r
+\r
+For best results apply to an older Emacs the patches from\r
+  ftp://ftp.math.ohio-state.edu/pub/users/ilya/cperl-mode/patches\r
+\(this upgrades syntax-parsing abilities of RMS Emaxen v19.34 and \r
+v20.2 up to the level of RMS Emacs v20.3 - a must for a good Perl\r
+mode.)  As of beginning of 2003, XEmacs may provide a similar ability.\r
+\r
+Get support packages choose-color.el (or font-lock-extra.el before\r
+19.30), imenu-go.el from the same place.  \(Look for other files there\r
+too... ;-).  Get a patch for imenu.el in 19.29.  Note that for 19.30 and\r
+later you should use choose-color.el *instead* of font-lock-extra.el\r
+\(and you will not get smart highlighting in C :-().\r
+\r
+Note that to enable Compile choices in the menu you need to install\r
+mode-compile.el.\r
+\r
+If your Emacs does not default to `cperl-mode' on Perl files, and you\r
+want it to: put the following into your .emacs file:\r
+\r
+  (autoload 'perl-mode \"cperl-mode\" \"alternate mode for editing Perl programs\" t)\r
+\r
+or\r
+\r
+  (defalias 'perl-mode 'cperl-mode)\r
+\r
+Get perl5-info from\r
+  $CPAN/doc/manual/info/perl-info.tar.gz\r
+older version was on\r
+  http://www.metronet.com:70/9/perlinfo/perl5/manual/perl5-info.tar.gz\r
+\r
+If you use imenu-go, run imenu on perl5-info buffer (you can do it\r
+from Perl menu).  If many files are related, generate TAGS files from\r
+Tools/Tags submenu in Perl menu.\r
+\r
+If some class structure is too complicated, use Tools/Hierarchy-view\r
+from Perl menu, or hierarchic view of imenu.  The second one uses the\r
+current buffer only, the first one requires generation of TAGS from\r
+Perl/Tools/Tags menu beforehand.\r
+\r
+Run Perl/Tools/Insert-spaces-if-needed to fix your lazy typing.\r
+\r
+Switch auto-help on/off with Perl/Tools/Auto-help.\r
+\r
+Though with contemporary Emaxen CPerl mode should maintain the correct\r
+parsing of Perl even when editing, sometimes it may be lost.  Fix this by\r
+\r
+  M-x norm RET\r
+\r
+or\r
+\r
+  \\[normal-mode]\r
+\r
+In cases of more severe confusion sometimes it is helpful to do\r
+\r
+  M-x load-l RET cperl-mode RET\r
+  M-x norm RET\r
+\r
+or\r
+\r
+  \\[load-library] cperl-mode RET\r
+  \\[normal-mode]\r
+\r
+Before reporting (non-)problems look in the problem section of online\r
+micro-docs on what I know about CPerl problems.")\r
+\r
+(defvar cperl-problems 'please-ignore-this-line\r
+  "Description of problems in CPerl mode.\r
+Some faces will not be shown on some versions of Emacs unless you\r
+install choose-color.el, available from\r
+   ftp://ftp.math.ohio-state.edu/pub/users/ilya/emacs/\r
+\r
+`fill-paragraph' on a comment may leave the point behind the\r
+paragraph.  Parsing of lines with several <<EOF is not implemented\r
+yet.\r
+\r
+Emacs had a _very_ restricted syntax parsing engine until RMS's Emacs\r
+20.1.  Most problems below are corrected starting from this version of\r
+Emacs, and all of them should be fixed in RMS's version 20.3.  (Or apply\r
+patches to Emacs 19.33/34 - see tips.)  XEmacs was very backward in\r
+this respect (until 2003).\r
+\r
+Note that even with newer Emacsen in some very rare cases the details\r
+of interaction of `font-lock' and syntaxification may be not cleaned\r
+up yet.  You may get slightly different colors basing on the order of\r
+fontification and syntaxification.  Say, the initial faces is correct,\r
+but editing the buffer breaks this.\r
+\r
+Even with older Emacsen CPerl mode tries to corrects some Emacs\r
+misunderstandings, however, for efficiency reasons the degree of\r
+correction is different for different operations.  The partially\r
+corrected problems are: POD sections, here-documents, regexps.  The\r
+operations are: highlighting, indentation, electric keywords, electric\r
+braces.\r
+\r
+This may be confusing, since the regexp s#//#/#\; may be highlighted\r
+as a comment, but it will be recognized as a regexp by the indentation\r
+code.  Or the opposite case, when a POD section is highlighted, but\r
+may break the indentation of the following code (though indentation\r
+should work if the balance of delimiters is not broken by POD).\r
+\r
+The main trick (to make $ a \"backslash\") makes constructions like\r
+${aaa} look like unbalanced braces.  The only trick I can think of is\r
+to insert it as $ {aaa} (legal in perl5, not in perl4).\r
+\r
+Similar problems arise in regexps, when /(\\s|$)/ should be rewritten\r
+as /($|\\s)/.  Note that such a transposition is not always possible.\r
+\r
+The solution is to upgrade your Emacs or patch an older one.  Note\r
+that RMS's 20.2 has some bugs related to `syntax-table' text\r
+properties.  Patches are available on the main CPerl download site,\r
+and on CPAN.\r
+\r
+If these bugs cannot be fixed on your machine (say, you have an inferior\r
+environment and cannot recompile), you may still disable all the fancy stuff\r
+via `cperl-use-syntax-table-text-property'.")\r
+\r
+(defvar cperl-non-problems 'please-ignore-this-line\r
+"As you know from `problems' section, Perl syntax is too hard for CPerl on \r
+older Emacsen.  Here is what you can do if you cannot upgrade, or if\r
+you want to switch off these capabilities on RMS Emacs 20.2 (+patches) or 20.3\r
+or better.  Please skip this docs if you run a capable Emacs already.\r
+\r
+Most of the time, if you write your own code, you may find an equivalent\r
+\(and almost as readable) expression (what is discussed below is usually\r
+not relevant on newer Emacsen, since they can do it automatically).\r
+\r
+Try to help CPerl: add comments with embedded quotes to fix CPerl\r
+misunderstandings about the end of quotation:\r
+\r
+$a='500$';      # ';\r
+\r
+You won't need it too often.  The reason: $ \"quotes\" the following\r
+character (this saves a life a lot of times in CPerl), thus due to\r
+Emacs parsing rules it does not consider tick (i.e., ' ) after a\r
+dollar as a closing one, but as a usual character.  This is usually\r
+correct, but not in the above context.\r
+\r
+Even with older Emacsen the indentation code is pretty wise.  The only\r
+drawback is that it relied on Emacs parsing to find matching\r
+parentheses.  And Emacs *could not* match parentheses in Perl 100%\r
+correctly.  So\r
+       1 if s#//#/#;\r
+would not break indentation, but\r
+       1 if ( s#//#/# );\r
+would.  Upgrade.\r
+\r
+By similar reasons\r
+       s\"abc\"def\";\r
+could confuse CPerl a lot.\r
+\r
+If you still get wrong indentation in situation that you think the\r
+code should be able to parse, try:\r
+\r
+a) Check what Emacs thinks about balance of your parentheses.\r
+b) Supply the code to me (IZ).\r
+\r
+Pods were treated _very_ rudimentally.  Here-documents were not\r
+treated at all (except highlighting and inhibiting indentation).  Upgrade.\r
+\r
+To speed up coloring the following compromises exist:\r
+   a) sub in $mypackage::sub may be highlighted.\r
+   b) -z in [a-z] may be highlighted.\r
+   c) if your regexp contains a keyword (like \"s\"), it may be highlighted.\r
+\r
+\r
+Imenu in 19.31 is broken.  Set `imenu-use-keymap-menu' to t, and remove\r
+`car' before `imenu-choose-buffer-index' in `imenu'.\r
+`imenu-add-to-menubar' in 20.2 is broken.  \r
+A lot of things on XEmacs may be broken too, judging by bug reports I\r
+receive.  Note that some releases of XEmacs are better than the others\r
+as far as bugs reports I see are concerned.")\r
+\r
+(defvar cperl-praise 'please-ignore-this-line\r
+  "Advantages of CPerl mode.\r
+\r
+0) It uses the newest `syntax-table' property ;-);\r
+\r
+1) It does 99% of Perl syntax correct (as opposed to 80-90% in Perl\r
+mode - but the latter number may have improved too in last years) even\r
+with old Emaxen which do not support `syntax-table' property.\r
+\r
+When using `syntax-table' property for syntax assist hints, it should\r
+handle 99.995% of lines correct - or somesuch.  It automatically\r
+updates syntax assist hints when you edit your script.\r
+\r
+2) It is generally believed to be \"the most user-friendly Emacs\r
+package\" whatever it may mean (I doubt that the people who say similar\r
+things tried _all_ the rest of Emacs ;-), but this was not a lonely\r
+voice);\r
+\r
+3) Everything is customizable, one-by-one or in a big sweep;\r
+\r
+4) It has many easily-accessable \"tools\":\r
+        a) Can run program, check syntax, start debugger;\r
+        b) Can lineup vertically \"middles\" of rows, like `=' in\r
+                a  = b;\r
+                cc = d;\r
+        c) Can insert spaces where this impoves readability (in one\r
+                interactive sweep over the buffer);\r
+        d) Has support for imenu, including:\r
+                1) Separate unordered list of \"interesting places\";\r
+                2) Separate TOC of POD sections;\r
+                3) Separate list of packages;\r
+                4) Hierarchical view of methods in (sub)packages;\r
+                5) and functions (by the full name - with package);\r
+        e) Has an interface to INFO docs for Perl; The interface is\r
+                very flexible, including shrink-wrapping of\r
+                documentation buffer/frame;\r
+        f) Has a builtin list of one-line explanations for perl constructs.\r
+        g) Can show these explanations if you stay long enough at the\r
+                corresponding place (or on demand);\r
+        h) Has an enhanced fontification (using 3 or 4 additional faces\r
+                comparing to font-lock - basically, different\r
+                namespaces in Perl have different colors);\r
+        i) Can construct TAGS basing on its knowledge of Perl syntax,\r
+                the standard menu has 6 different way to generate\r
+                TAGS (if \"by directory\", .xs files - with C-language\r
+                bindings - are included in the scan);\r
+        j) Can build a hierarchical view of classes (via imenu) basing\r
+                on generated TAGS file;\r
+        k) Has electric parentheses, electric newlines, uses Abbrev\r
+                for electric logical constructs\r
+                        while () {}\r
+                with different styles of expansion (context sensitive\r
+                to be not so bothering).  Electric parentheses behave\r
+                \"as they should\" in a presence of a visible region.\r
+        l) Changes msb.el \"on the fly\" to insert a group \"Perl files\";\r
+        m) Can convert from\r
+               if (A) { B }\r
+          to\r
+               B if A;\r
+\r
+        n) Highlights (by user-choice) either 3-delimiters constructs\r
+          (such as tr/a/b/), or regular expressions and `y/tr';\r
+       o) Highlights trailing whitespace;\r
+       p) Is able to manipulate Perl Regular Expressions to ease\r
+          conversion to a more readable form.\r
+\r
+5) The indentation engine was very smart, but most of tricks may be\r
+not needed anymore with the support for `syntax-table' property.  Has\r
+progress indicator for indentation (with `imenu' loaded).\r
+\r
+6) Indent-region improves inline-comments as well; also corrects\r
+whitespace *inside* the conditional/loop constructs.\r
+\r
+7) Fill-paragraph correctly handles multi-line comments;\r
+\r
+8) Can switch to different indentation styles by one command, and restore\r
+the settings present before the switch.\r
+\r
+9) When doing indentation of control constructs, may correct\r
+line-breaks/spacing between elements of the construct.\r
+\r
+10) Uses a linear-time algorith for indentation of regions (on Emaxen with\r
+capable syntax engines).")\r
+\r
+(defvar cperl-speed 'please-ignore-this-line\r
+  "This is an incomplete compendium of what is available in other parts\r
+of CPerl documentation.  (Please inform me if I skept anything.)\r
+\r
+There is a perception that CPerl is slower than alternatives.  This part\r
+of documentation is designed to overcome this misconception.\r
+\r
+*By default* CPerl tries to enable the most comfortable settings.\r
+From most points of view, correctly working package is infinitely more\r
+comfortable than a non-correctly working one, thus by default CPerl\r
+prefers correctness over speed.  Below is the guide how to change\r
+settings if your preferences are different.\r
+\r
+A)  Speed of loading the file.  When loading file, CPerl may perform a\r
+scan which indicates places which cannot be parsed by primitive Emacs\r
+syntax-parsing routines, and marks them up so that either\r
+\r
+    A1) CPerl may work around these deficiencies (for big chunks, mostly\r
+        PODs and HERE-documents), or\r
+    A2) On capable Emaxen CPerl will use improved syntax-handlings\r
+       which reads mark-up hints directly.\r
+\r
+    The scan in case A2 is much more comprehensive, thus may be slower.\r
+\r
+    User can disable syntax-engine-helping scan of A2 by setting\r
+       `cperl-use-syntax-table-text-property'\r
+    variable to nil (if it is set to t).\r
+\r
+    One can disable the scan altogether (both A1 and A2) by setting\r
+       `cperl-pod-here-scan'\r
+    to nil.\r
+\r
+B) Speed of editing operations.\r
+\r
+    One can add a (minor) speedup to editing operations by setting\r
+       `cperl-use-syntax-table-text-property'\r
+    variable to nil (if it is set to t).  This will disable\r
+    syntax-engine-helping scan, thus will make many more Perl\r
+    constructs be wrongly recognized by CPerl, thus may lead to\r
+    wrongly matched parentheses, wrong indentation, etc.\r
+\r
+    One can unset `cperl-syntaxify-unwind'.  This might speed up editing\r
+    of, say, long POD sections.")\r
+\r
+(defvar cperl-tips-faces 'please-ignore-this-line\r
+  "CPerl mode uses following faces for highlighting:\r
+\r
+  `cperl-array-face'           Array names\r
+  `cperl-hash-face'            Hash names\r
+  `font-lock-comment-face'     Comments, PODs and whatever is considered\r
+                               syntaxically to be not code\r
+  `font-lock-constant-face'    HERE-doc delimiters, labels, delimiters of\r
+                               2-arg operators s/y/tr/ or of RExen,\r
+  `font-lock-function-name-face' Special-cased m// and s//foo/, _ as\r
+                               a target of a file tests, file tests,\r
+                               subroutine names at the moment of definition\r
+                               (except those conflicting with Perl operators),\r
+                               package names (when recognized), format names\r
+  `font-lock-keyword-face'     Control flow switch constructs, declarators\r
+  `cperl-nonoverridable-face'  Non-overridable keywords, modifiers of RExen\r
+  `font-lock-string-face'      Strings, qw() constructs, RExen, POD sections,\r
+                               literal parts and the terminator of formats\r
+                               and whatever is syntaxically considered\r
+                               as string literals\r
+  `font-lock-type-face'                Overridable keywords\r
+  `font-lock-variable-name-face' Variable declarations, indirect array and\r
+                               hash names, POD headers/item names\r
+  `cperl-invalid-face'         Trailing whitespace\r
+\r
+Note that in several situations the highlighting tries to inform about\r
+possible confusion, such as different colors for function names in\r
+declarations depending on what they (do not) override, or special cases\r
+m// and s/// which do not do what one would expect them to do.\r
+\r
+Help with best setup of these faces for printout requested (for each of\r
+the faces: please specify bold, italic, underline, shadow and box.)\r
+\r
+\(Not finished.)")\r
+\r
+\f\r
+\r
+;;; Portability stuff:\r
+\r
+(defmacro cperl-define-key (emacs-key definition &optional xemacs-key)\r
+  (` (define-key cperl-mode-map\r
+       (, (if xemacs-key\r
+             (` (if cperl-xemacs-p (, xemacs-key) (, emacs-key)))\r
+           emacs-key))\r
+       (, definition))))\r
+\r
+(defvar cperl-del-back-ch\r
+  (car (append (where-is-internal 'delete-backward-char)\r
+              (where-is-internal 'backward-delete-char-untabify)))\r
+  "Character generated by key bound to `delete-backward-char'.")\r
+\r
+(and (vectorp cperl-del-back-ch) (= (length cperl-del-back-ch) 1)\r
+     (setq cperl-del-back-ch (aref cperl-del-back-ch 0)))\r
+\r
+(defun cperl-mark-active () (mark))    ; Avoid undefined warning\r
+(if cperl-xemacs-p\r
+    (progn\r
+      ;; "Active regions" are on: use region only if active\r
+      ;; "Active regions" are off: use region unconditionally\r
+      (defun cperl-use-region-p ()\r
+       (if zmacs-regions (mark) t)))\r
+  (defun cperl-use-region-p ()\r
+    (if transient-mark-mode mark-active t))\r
+  (defun cperl-mark-active () mark-active))\r
+\r
+(defsubst cperl-enable-font-lock ()\r
+  cperl-can-font-lock)\r
+\r
+(defun cperl-putback-char (c)          ; Emacs 19\r
+  (set 'unread-command-events (list c))) ; Avoid undefined warning\r
+\r
+(if (boundp 'unread-command-events)\r
+    (if cperl-xemacs-p\r
+       (defun cperl-putback-char (c)   ; XEmacs >= 19.12\r
+         (setq unread-command-events (list (eval '(character-to-event c))))))\r
+  (defun cperl-putback-char (c)                ; XEmacs <= 19.11\r
+    (set 'unread-command-event (eval '(character-to-event c))))) ; Avoid warnings\r
+\r
+(or (fboundp 'uncomment-region)\r
+    (defun uncomment-region (beg end)\r
+      (interactive "r")\r
+      (comment-region beg end -1)))\r
+\r
+(defvar cperl-do-not-fontify\r
+  (if (string< emacs-version "19.30")\r
+      'fontified\r
+    'lazy-lock)\r
+  "Text property which inhibits refontification.")\r
+\r
+(defsubst cperl-put-do-not-fontify (from to &optional post)\r
+  ;; If POST, do not do it with postponed fontification\r
+  (if (and post cperl-syntaxify-by-font-lock)\r
+      nil\r
+    (put-text-property (max (point-min) (1- from))\r
+                      to cperl-do-not-fontify t)))\r
+\r
+(defcustom cperl-mode-hook nil\r
+  "Hook run by CPerl mode."\r
+  :type 'hook\r
+  :group 'cperl)\r
+\r
+(defvar cperl-syntax-state nil)\r
+(defvar cperl-syntax-done-to nil)\r
+(defvar cperl-emacs-can-parse (> (length (save-excursion\r
+                                          (parse-partial-sexp (point) (point)))) 9))\r
+\f\r
+;; Make customization possible "in reverse"\r
+(defsubst cperl-val (symbol &optional default hairy)\r
+  (cond\r
+   ((eq (symbol-value symbol) 'null) default)\r
+   (cperl-hairy (or hairy t))\r
+   (t (symbol-value symbol))))\r
+\f\r
+;;; Probably it is too late to set these guys already, but it can help later:\r
+\r
+(and cperl-clobber-mode-lists\r
+     (setq auto-mode-alist\r
+      (append '(("\\.\\([pP][Llm]\\|al\\)$" . perl-mode))  auto-mode-alist ))\r
+     (and (boundp 'interpreter-mode-alist)\r
+         (setq interpreter-mode-alist (append interpreter-mode-alist\r
+                                              '(("miniperl" . perl-mode))))))\r
+(if (fboundp 'eval-when-compile)\r
+    (eval-when-compile\r
+      (mapcar (lambda (p)\r
+               (condition-case nil\r
+                   (require p)\r
+                 (error nil)))\r
+             '(imenu easymenu etags timer man info))\r
+      (if (fboundp 'ps-extend-face-list)\r
+         (defmacro cperl-ps-extend-face-list (arg)\r
+           (` (ps-extend-face-list (, arg))))\r
+       (defmacro cperl-ps-extend-face-list (arg)\r
+         (` (error "This version of Emacs has no `ps-extend-face-list'"))))\r
+      ;; Calling `cperl-enable-font-lock' below doesn't compile on XEmacs,\r
+      ;; macros instead of defsubsts don't work on Emacs, so we do the\r
+      ;; expansion manually.  Any other suggestions?\r
+      (if cperl-can-font-lock\r
+         (require 'font-lock))\r
+      (require 'cl)))\r
+\r
+(defvar cperl-mode-abbrev-table nil\r
+  "Abbrev table in use in CPerl mode buffers.")\r
+\r
+(add-hook 'edit-var-mode-alist '(perl-mode (regexp . "^cperl-")))\r
+\r
+(defvar cperl-mode-map () "Keymap used in CPerl mode.")\r
+\r
+(if cperl-mode-map nil\r
+  (setq cperl-mode-map (make-sparse-keymap))\r
+  (cperl-define-key "{" 'cperl-electric-lbrace)\r
+  (cperl-define-key "[" 'cperl-electric-paren)\r
+  (cperl-define-key "(" 'cperl-electric-paren)\r
+  (cperl-define-key "<" 'cperl-electric-paren)\r
+  (cperl-define-key "}" 'cperl-electric-brace)\r
+  (cperl-define-key "]" 'cperl-electric-rparen)\r
+  (cperl-define-key ")" 'cperl-electric-rparen)\r
+  (cperl-define-key ";" 'cperl-electric-semi)\r
+  (cperl-define-key ":" 'cperl-electric-terminator)\r
+  (cperl-define-key "\C-j" 'newline-and-indent)\r
+  (cperl-define-key "\C-c\C-j" 'cperl-linefeed)\r
+  (cperl-define-key "\C-c\C-t" 'cperl-invert-if-unless)\r
+  (cperl-define-key "\C-c\C-a" 'cperl-toggle-auto-newline)\r
+  (cperl-define-key "\C-c\C-k" 'cperl-toggle-abbrev)\r
+  (cperl-define-key "\C-c\C-w" 'cperl-toggle-construct-fix)\r
+  (cperl-define-key "\C-c\C-f" 'auto-fill-mode)\r
+  (cperl-define-key "\C-c\C-e" 'cperl-toggle-electric)\r
+  (cperl-define-key "\C-c\C-ha" 'cperl-toggle-autohelp)\r
+  (cperl-define-key "\e\C-q" 'cperl-indent-exp) ; Usually not bound\r
+  (cperl-define-key [?\C-\M-\|] 'cperl-lineup\r
+                   [(control meta |)])\r
+  ;;(cperl-define-key "\M-q" 'cperl-fill-paragraph)\r
+  ;;(cperl-define-key "\e;" 'cperl-indent-for-comment)\r
+  (cperl-define-key "\177" 'cperl-electric-backspace)\r
+  (cperl-define-key "\t" 'cperl-indent-command)\r
+  ;; don't clobber the backspace binding:\r
+  (cperl-define-key "\C-c\C-hF" 'cperl-info-on-command\r
+                   [(control c) (control h) F])\r
+  (if (cperl-val 'cperl-clobber-lisp-bindings)\r
+      (progn\r
+       (cperl-define-key "\C-hf"\r
+                         ;;(concat (char-to-string help-char) "f") ; does not work\r
+                         'cperl-info-on-command\r
+                         [(control h) f])\r
+       (cperl-define-key "\C-hv"\r
+                         ;;(concat (char-to-string help-char) "v") ; does not work\r
+                         'cperl-get-help\r
+                         [(control h) v])\r
+       (cperl-define-key "\C-c\C-hf"\r
+                         ;;(concat (char-to-string help-char) "f") ; does not work\r
+                         (key-binding "\C-hf")\r
+                         [(control c) (control h) f])\r
+       (cperl-define-key "\C-c\C-hv"\r
+                         ;;(concat (char-to-string help-char) "v") ; does not work\r
+                         (key-binding "\C-hv")\r
+                         [(control c) (control h) v]))\r
+    (cperl-define-key "\C-c\C-hf" 'cperl-info-on-current-command\r
+                     [(control c) (control h) f])\r
+    (cperl-define-key "\C-c\C-hv"\r
+                     ;;(concat (char-to-string help-char) "v") ; does not work\r
+                     'cperl-get-help\r
+                     [(control c) (control h) v]))\r
+  (if (and cperl-xemacs-p\r
+          (<= emacs-minor-version 11) (<= emacs-major-version 19))\r
+      (progn\r
+       ;; substitute-key-definition is usefulness-deenhanced...\r
+       (cperl-define-key "\M-q" 'cperl-fill-paragraph)\r
+       (cperl-define-key "\e;" 'cperl-indent-for-comment)\r
+       (cperl-define-key "\e\C-\\" 'cperl-indent-region))\r
+    (substitute-key-definition\r
+     'indent-sexp 'cperl-indent-exp\r
+     cperl-mode-map global-map)\r
+    (substitute-key-definition\r
+     'fill-paragraph 'cperl-fill-paragraph\r
+     cperl-mode-map global-map)\r
+    (substitute-key-definition\r
+     'indent-region 'cperl-indent-region\r
+     cperl-mode-map global-map)\r
+    (substitute-key-definition\r
+     'indent-for-comment 'cperl-indent-for-comment\r
+     cperl-mode-map global-map)))\r
+\r
+(defvar cperl-menu)\r
+(defvar cperl-lazy-installed)\r
+(defvar cperl-old-style nil)\r
+(condition-case nil\r
+    (progn\r
+      (require 'easymenu)\r
+      (easy-menu-define\r
+       cperl-menu cperl-mode-map "Menu for CPerl mode"\r
+       '("Perl"\r
+        ["Beginning of function" beginning-of-defun t]\r
+        ["End of function" end-of-defun t]\r
+        ["Mark function" mark-defun t]\r
+        ["Indent expression" cperl-indent-exp t]\r
+        ["Fill paragraph/comment" cperl-fill-paragraph t]\r
+        "----"\r
+        ["Line up a construction" cperl-lineup (cperl-use-region-p)]\r
+        ["Invert if/unless/while etc" cperl-invert-if-unless t]\r
+        ("Regexp"\r
+         ["Beautify" cperl-beautify-regexp\r
+          cperl-use-syntax-table-text-property]\r
+         ["Beautify one level deep" (cperl-beautify-regexp 1)\r
+          cperl-use-syntax-table-text-property]\r
+         ["Beautify a group" cperl-beautify-level\r
+          cperl-use-syntax-table-text-property]\r
+         ["Beautify a group one level deep" (cperl-beautify-level 1)\r
+          cperl-use-syntax-table-text-property]\r
+         ["Contract a group" cperl-contract-level\r
+          cperl-use-syntax-table-text-property]\r
+         ["Contract groups" cperl-contract-levels\r
+          cperl-use-syntax-table-text-property])\r
+        ["Refresh \"hard\" constructions" cperl-find-pods-heres t]\r
+        "----"\r
+        ["Indent region" cperl-indent-region (cperl-use-region-p)]\r
+        ["Comment region" cperl-comment-region (cperl-use-region-p)]\r
+        ["Uncomment region" cperl-uncomment-region (cperl-use-region-p)]\r
+        "----"\r
+        ["Run" mode-compile (fboundp 'mode-compile)]\r
+        ["Kill" mode-compile-kill (and (fboundp 'mode-compile-kill)\r
+                                       (get-buffer "*compilation*"))]\r
+        ["Next error" next-error (get-buffer "*compilation*")]\r
+        ["Check syntax" cperl-check-syntax (fboundp 'mode-compile)]\r
+        "----"\r
+        ["Debugger" cperl-db t]\r
+        "----"\r
+        ("Tools"\r
+         ["Imenu" imenu (fboundp 'imenu)]\r
+         ["Insert spaces if needed" cperl-find-bad-style t]\r
+         ["Class Hierarchy from TAGS" cperl-tags-hier-init t]\r
+         ;;["Update classes" (cperl-tags-hier-init t) tags-table-list]\r
+         ["CPerl pretty print (exprmntl)" cperl-ps-print \r
+          (fboundp 'ps-extend-face-list)]\r
+         ["Imenu on info" cperl-imenu-on-info (featurep 'imenu)]\r
+         ("Tags"\r
+;;;         ["Create tags for current file" cperl-etags t]\r
+;;;         ["Add tags for current file" (cperl-etags t) t]\r
+;;;         ["Create tags for Perl files in directory" (cperl-etags nil t) t]\r
+;;;         ["Add tags for Perl files in directory" (cperl-etags t t) t]\r
+;;;         ["Create tags for Perl files in (sub)directories"\r
+;;;          (cperl-etags nil 'recursive) t]\r
+;;;         ["Add tags for Perl files in (sub)directories"\r
+;;;          (cperl-etags t 'recursive) t])\r
+;;;; cperl-write-tags (&optional file erase recurse dir inbuffer)\r
+          ["Create tags for current file" (cperl-write-tags nil t) t]\r
+          ["Add tags for current file" (cperl-write-tags) t]\r
+          ["Create tags for Perl files in directory"\r
+           (cperl-write-tags nil t nil t) t]\r
+          ["Add tags for Perl files in directory"\r
+           (cperl-write-tags nil nil nil t) t]\r
+          ["Create tags for Perl files in (sub)directories"\r
+           (cperl-write-tags nil t t t) t]\r
+          ["Add tags for Perl files in (sub)directories"\r
+           (cperl-write-tags nil nil t t) t]))\r
+        ("Perl docs"\r
+         ["Define word at point" imenu-go-find-at-position \r
+          (fboundp 'imenu-go-find-at-position)]\r
+         ["Help on function" cperl-info-on-command t]\r
+         ["Help on function at point" cperl-info-on-current-command t]\r
+         ["Help on symbol at point" cperl-get-help t]\r
+         ["Perldoc" cperl-perldoc t]\r
+         ["Perldoc on word at point" cperl-perldoc-at-point t]\r
+         ["View manpage of POD in this file" cperl-build-manpage t]\r
+         ["Auto-help on" cperl-lazy-install \r
+          (and (fboundp 'run-with-idle-timer)\r
+               (not cperl-lazy-installed))]\r
+         ["Auto-help off" cperl-lazy-unstall\r
+          (and (fboundp 'run-with-idle-timer)\r
+               cperl-lazy-installed)])\r
+        ("Toggle..."\r
+         ["Auto newline" cperl-toggle-auto-newline t]\r
+         ["Electric parens" cperl-toggle-electric t]\r
+         ["Electric keywords" cperl-toggle-abbrev t]\r
+         ["Fix whitespace on indent" cperl-toggle-construct-fix t]\r
+         ["Auto-help on Perl constructs" cperl-toggle-autohelp t]\r
+         ["Auto fill" auto-fill-mode t]) \r
+        ("Indent styles..."\r
+         ["CPerl" (cperl-set-style "CPerl") t]\r
+         ["PerlStyle" (cperl-set-style "PerlStyle") t]\r
+         ["GNU" (cperl-set-style "GNU") t]\r
+         ["C++" (cperl-set-style "C++") t]\r
+         ["FSF" (cperl-set-style "FSF") t]\r
+         ["BSD" (cperl-set-style "BSD") t]\r
+         ["Whitesmith" (cperl-set-style "Whitesmith") t]\r
+         ["Current" (cperl-set-style "Current") t]\r
+         ["Memorized" (cperl-set-style-back) cperl-old-style])\r
+        ("Micro-docs"\r
+         ["Tips" (describe-variable 'cperl-tips) t]\r
+         ["Problems" (describe-variable 'cperl-problems) t]\r
+         ["Non-problems" (describe-variable 'cperl-non-problems) t]\r
+         ["Speed" (describe-variable 'cperl-speed) t]\r
+         ["Praise" (describe-variable 'cperl-praise) t]\r
+         ["Faces" (describe-variable 'cperl-tips-faces) t]\r
+         ["CPerl mode" (describe-function 'cperl-mode) t]\r
+         ["CPerl version" \r
+          (message "The version of master-file for this CPerl is %s" \r
+                   cperl-version) t]))))\r
+  (error nil))\r
+\r
+(autoload 'c-macro-expand "cmacexp"\r
+  "Display the result of expanding all C macros occurring in the region.\r
+The expansion is entirely correct because it uses the C preprocessor."\r
+  t)\r
+\r
+(defvar cperl-imenu--function-name-regexp-perl\r
+  (concat\r
+   "^\\("\r
+       "[ \t]*\\(sub\\|package\\)[ \t\n]+\\([a-zA-Z_0-9:']+\\)[ \t]*\\(([^()]*)[ \t]*\\)?"\r
+   "\\|"\r
+       "=head\\([12]\\)[ \t]+\\([^\n]+\\)$"\r
+   "\\)"))\r
+\r
+(defvar cperl-outline-regexp\r
+  (concat cperl-imenu--function-name-regexp-perl "\\|" "\\`"))\r
+\r
+(defvar cperl-mode-syntax-table nil\r
+  "Syntax table in use in CPerl mode buffers.")\r
+\r
+(defvar cperl-string-syntax-table nil\r
+  "Syntax table in use in CPerl mode string-like chunks.")\r
+\r
+(if cperl-mode-syntax-table\r
+    ()\r
+  (setq cperl-mode-syntax-table (make-syntax-table))\r
+  (modify-syntax-entry ?\\ "\\" cperl-mode-syntax-table)\r
+  (modify-syntax-entry ?/ "." cperl-mode-syntax-table)\r
+  (modify-syntax-entry ?* "." cperl-mode-syntax-table)\r
+  (modify-syntax-entry ?+ "." cperl-mode-syntax-table)\r
+  (modify-syntax-entry ?- "." cperl-mode-syntax-table)\r
+  (modify-syntax-entry ?= "." cperl-mode-syntax-table)\r
+  (modify-syntax-entry ?% "." cperl-mode-syntax-table)\r
+  (modify-syntax-entry ?< "." cperl-mode-syntax-table)\r
+  (modify-syntax-entry ?> "." cperl-mode-syntax-table)\r
+  (modify-syntax-entry ?& "." cperl-mode-syntax-table)\r
+  (modify-syntax-entry ?$ "\\" cperl-mode-syntax-table)\r
+  (modify-syntax-entry ?\n ">" cperl-mode-syntax-table)\r
+  (modify-syntax-entry ?# "<" cperl-mode-syntax-table)\r
+  (modify-syntax-entry ?' "\"" cperl-mode-syntax-table)\r
+  (modify-syntax-entry ?` "\"" cperl-mode-syntax-table)\r
+  (if cperl-under-as-char\r
+      (modify-syntax-entry ?_ "w" cperl-mode-syntax-table))\r
+  (modify-syntax-entry ?: "_" cperl-mode-syntax-table)\r
+  (modify-syntax-entry ?| "." cperl-mode-syntax-table)\r
+  (setq cperl-string-syntax-table (copy-syntax-table cperl-mode-syntax-table))\r
+  (modify-syntax-entry ?$ "." cperl-string-syntax-table)\r
+  (modify-syntax-entry ?# "." cperl-string-syntax-table)) ; (?# comment )\r
+\r
+\r
+\f\r
+;; provide an alias for working with emacs 19.  the perl-mode that comes\r
+;; with it is really bad, and this lets us seamlessly replace it.\r
+;;;###autoload\r
+(fset 'perl-mode 'cperl-mode)\r
+(defvar cperl-faces-init nil)\r
+;; Fix for msb.el\r
+(defvar cperl-msb-fixed nil)\r
+(defvar font-lock-syntactic-keywords)\r
+(defvar perl-font-lock-keywords)\r
+(defvar perl-font-lock-keywords-1)\r
+(defvar perl-font-lock-keywords-2)\r
+(defvar outline-level)\r
+(if (fboundp 'defvaralias)\r
+    (let ((f 'defvaralias)) ; Some functions deduce stuff from the mode name...\r
+      (funcall f 'cperl-font-lock-keywords   'perl-font-lock-keywords)\r
+      (funcall f 'cperl-font-lock-keywords-1 'perl-font-lock-keywords-1)\r
+      (funcall f 'cperl-font-lock-keywords-2 'perl-font-lock-keywords-2)))\r
+\r
+(defvar cperl-use-major-mode 'perl-mode)\r
+\r
+;;;###autoload\r
+(defun cperl-mode ()\r
+  "Major mode for editing Perl code.\r
+Expression and list commands understand all C brackets.\r
+Tab indents for Perl code.\r
+Paragraphs are separated by blank lines only.\r
+Delete converts tabs to spaces as it moves back.\r
+\r
+Various characters in Perl almost always come in pairs: {}, (), [],\r
+sometimes <>.  When the user types the first, she gets the second as\r
+well, with optional special formatting done on {}.  (Disabled by\r
+default.)  You can always quote (with \\[quoted-insert]) the left\r
+\"paren\" to avoid the expansion.  The processing of < is special,\r
+since most the time you mean \"less\".  CPerl mode tries to guess\r
+whether you want to type pair <>, and inserts is if it\r
+appropriate.  You can set `cperl-electric-parens-string' to the string that\r
+contains the parenths from the above list you want to be electrical.\r
+Electricity of parenths is controlled by `cperl-electric-parens'.\r
+You may also set `cperl-electric-parens-mark' to have electric parens\r
+look for active mark and \"embrace\" a region if possible.'\r
+\r
+CPerl mode provides expansion of the Perl control constructs:\r
+\r
+   if, else, elsif, unless, while, until, continue, do,\r
+   for, foreach, formy and foreachmy.\r
+\r
+and POD directives (Disabled by default, see `cperl-electric-keywords'.)\r
+\r
+The user types the keyword immediately followed by a space, which\r
+causes the construct to be expanded, and the point is positioned where\r
+she is most likely to want to be.  eg. when the user types a space\r
+following \"if\" the following appears in the buffer: if () { or if ()\r
+} { } and the cursor is between the parentheses.  The user can then\r
+type some boolean expression within the parens.  Having done that,\r
+typing \\[cperl-linefeed] places you - appropriately indented - on a\r
+new line between the braces (if you typed \\[cperl-linefeed] in a POD\r
+directive line, then appropriate number of new lines is inserted).\r
+\r
+If CPerl decides that you want to insert \"English\" style construct like\r
+\r
+            bite if angry;\r
+\r
+it will not do any expansion.  See also help on variable\r
+`cperl-extra-newline-before-brace'.  (Note that one can switch the\r
+help message on expansion by setting `cperl-message-electric-keyword'\r
+to nil.)\r
+\r
+\\[cperl-linefeed] is a convenience replacement for typing carriage\r
+return.  It places you in the next line with proper indentation, or if\r
+you type it inside the inline block of control construct, like\r
+\r
+            foreach (@lines) {print; print}\r
+\r
+and you are on a boundary of a statement inside braces, it will\r
+transform the construct into a multiline and will place you into an\r
+appropriately indented blank line.  If you need a usual\r
+`newline-and-indent' behaviour, it is on \\[newline-and-indent],\r
+see documentation on `cperl-electric-linefeed'.\r
+\r
+Use \\[cperl-invert-if-unless] to change a construction of the form\r
+\r
+           if (A) { B }\r
+\r
+into\r
+\r
+            B if A;\r
+\r
+\\{cperl-mode-map}\r
+\r
+Setting the variable `cperl-font-lock' to t switches on font-lock-mode\r
+\(even with older Emacsen), `cperl-electric-lbrace-space' to t switches\r
+on electric space between $ and {, `cperl-electric-parens-string' is\r
+the string that contains parentheses that should be electric in CPerl\r
+\(see also `cperl-electric-parens-mark' and `cperl-electric-parens'),\r
+setting `cperl-electric-keywords' enables electric expansion of\r
+control structures in CPerl.  `cperl-electric-linefeed' governs which\r
+one of two linefeed behavior is preferable.  You can enable all these\r
+options simultaneously (recommended mode of use) by setting\r
+`cperl-hairy' to t.  In this case you can switch separate options off\r
+by setting them to `null'.  Note that one may undo the extra\r
+whitespace inserted by semis and braces in `auto-newline'-mode by\r
+consequent \\[cperl-electric-backspace].\r
+\r
+If your site has perl5 documentation in info format, you can use commands\r
+\\[cperl-info-on-current-command] and \\[cperl-info-on-command] to access it.\r
+These keys run commands `cperl-info-on-current-command' and\r
+`cperl-info-on-command', which one is which is controlled by variable\r
+`cperl-info-on-command-no-prompt' and `cperl-clobber-lisp-bindings'\r
+\(in turn affected by `cperl-hairy').\r
+\r
+Even if you have no info-format documentation, short one-liner-style\r
+help is available on \\[cperl-get-help], and one can run perldoc or\r
+man via menu.\r
+\r
+It is possible to show this help automatically after some idle time.\r
+This is regulated by variable `cperl-lazy-help-time'.  Default with\r
+`cperl-hairy' (if the value of `cperl-lazy-help-time' is nil) is 5\r
+secs idle time .  It is also possible to switch this on/off from the\r
+menu, or via \\[cperl-toggle-autohelp].  Requires `run-with-idle-timer'.\r
+\r
+Use \\[cperl-lineup] to vertically lineup some construction - put the\r
+beginning of the region at the start of construction, and make region\r
+span the needed amount of lines.\r
+\r
+Variables `cperl-pod-here-scan', `cperl-pod-here-fontify',\r
+`cperl-pod-face', `cperl-pod-head-face' control processing of POD and\r
+here-docs sections.  With capable Emaxen results of scan are used\r
+for indentation too, otherwise they are used for highlighting only.\r
+\r
+Variables controlling indentation style:\r
+ `cperl-tab-always-indent'\r
+    Non-nil means TAB in CPerl mode should always reindent the current line,\r
+    regardless of where in the line point is when the TAB command is used.\r
+ `cperl-indent-left-aligned-comments'\r
+    Non-nil means that the comment starting in leftmost column should indent.\r
+ `cperl-auto-newline'\r
+    Non-nil means automatically newline before and after braces,\r
+    and after colons and semicolons, inserted in Perl code.  The following\r
+    \\[cperl-electric-backspace] will remove the inserted whitespace.\r
+    Insertion after colons requires both this variable and\r
+    `cperl-auto-newline-after-colon' set.\r
+ `cperl-auto-newline-after-colon'\r
+    Non-nil means automatically newline even after colons.\r
+    Subject to `cperl-auto-newline' setting.\r
+ `cperl-indent-level'\r
+    Indentation of Perl statements within surrounding block.\r
+    The surrounding block's indentation is the indentation\r
+    of the line on which the open-brace appears.\r
+ `cperl-continued-statement-offset'\r
+    Extra indentation given to a substatement, such as the\r
+    then-clause of an if, or body of a while, or just a statement continuation.\r
+ `cperl-continued-brace-offset'\r
+    Extra indentation given to a brace that starts a substatement.\r
+    This is in addition to `cperl-continued-statement-offset'.\r
+ `cperl-brace-offset'\r
+    Extra indentation for line if it starts with an open brace.\r
+ `cperl-brace-imaginary-offset'\r
+    An open brace following other text is treated as if it the line started\r
+    this far to the right of the actual line indentation.\r
+ `cperl-label-offset'\r
+    Extra indentation for line that is a label.\r
+ `cperl-min-label-indent'\r
+    Minimal indentation for line that is a label.\r
+\r
+Settings for K&R and BSD indentation styles are\r
+  `cperl-indent-level'                5    8\r
+  `cperl-continued-statement-offset'  5    8\r
+  `cperl-brace-offset'               -5   -8\r
+  `cperl-label-offset'               -5   -8\r
+\r
+CPerl knows several indentation styles, and may bulk set the\r
+corresponding variables.  Use \\[cperl-set-style] to do this.  Use\r
+\\[cperl-set-style-back] to restore the memorized preexisting values\r
+\(both available from menu).\r
+\r
+If `cperl-indent-level' is 0, the statement after opening brace in\r
+column 0 is indented on\r
+`cperl-brace-offset'+`cperl-continued-statement-offset'.\r
+\r
+Turning on CPerl mode calls the hooks in the variable `cperl-mode-hook'\r
+with no args.\r
+\r
+DO NOT FORGET to read micro-docs (available from `Perl' menu)\r
+or as help on variables `cperl-tips', `cperl-problems',\r
+`cperl-non-problems', `cperl-praise', `cperl-speed'."\r
+  (interactive)\r
+  (kill-all-local-variables)\r
+  (use-local-map cperl-mode-map)\r
+  (if (cperl-val 'cperl-electric-linefeed)\r
+      (progn\r
+       (local-set-key "\C-J" 'cperl-linefeed)\r
+       (local-set-key "\C-C\C-J" 'newline-and-indent)))\r
+  (if (and\r
+       (cperl-val 'cperl-clobber-lisp-bindings)\r
+       (cperl-val 'cperl-info-on-command-no-prompt))\r
+      (progn\r
+       ;; don't clobber the backspace binding:\r
+       (cperl-define-key "\C-hf" 'cperl-info-on-current-command [(control h) f])\r
+       (cperl-define-key "\C-c\C-hf" 'cperl-info-on-command\r
+                         [(control c) (control h) f])))\r
+  (setq major-mode cperl-use-major-mode)\r
+  (setq mode-name "CPerl")\r
+  (if (not cperl-mode-abbrev-table)\r
+      (let ((prev-a-c abbrevs-changed))\r
+       (define-abbrev-table 'cperl-mode-abbrev-table '(\r
+               ("if" "if" cperl-electric-keyword 0)\r
+               ("elsif" "elsif" cperl-electric-keyword 0)\r
+               ("while" "while" cperl-electric-keyword 0)\r
+               ("until" "until" cperl-electric-keyword 0)\r
+               ("unless" "unless" cperl-electric-keyword 0)\r
+               ("else" "else" cperl-electric-else 0)\r
+               ("continue" "continue" cperl-electric-else 0)\r
+               ("for" "for" cperl-electric-keyword 0)\r
+               ("foreach" "foreach" cperl-electric-keyword 0)\r
+               ("formy" "formy" cperl-electric-keyword 0)\r
+               ("foreachmy" "foreachmy" cperl-electric-keyword 0)\r
+               ("do" "do" cperl-electric-keyword 0)\r
+               ("=pod" "=pod" cperl-electric-pod 0)\r
+               ("=over" "=over" cperl-electric-pod 0)\r
+               ("=head1" "=head1" cperl-electric-pod 0)\r
+               ("=head2" "=head2" cperl-electric-pod 0)\r
+               ("pod" "pod" cperl-electric-pod 0)\r
+               ("over" "over" cperl-electric-pod 0)\r
+               ("head1" "head1" cperl-electric-pod 0)\r
+               ("head2" "head2" cperl-electric-pod 0)))\r
+       (setq abbrevs-changed prev-a-c)))\r
+  (setq local-abbrev-table cperl-mode-abbrev-table)\r
+  (abbrev-mode (if (cperl-val 'cperl-electric-keywords) 1 0))\r
+  (set-syntax-table cperl-mode-syntax-table)\r
+  (make-local-variable 'outline-regexp)\r
+  ;; (setq outline-regexp imenu-example--function-name-regexp-perl)\r
+  (setq outline-regexp cperl-outline-regexp)\r
+  (make-local-variable 'outline-level)\r
+  (setq outline-level 'cperl-outline-level)\r
+  (make-local-variable 'paragraph-start)\r
+  (setq paragraph-start (concat "^$\\|" page-delimiter))\r
+  (make-local-variable 'paragraph-separate)\r
+  (setq paragraph-separate paragraph-start)\r
+  (make-local-variable 'paragraph-ignore-fill-prefix)\r
+  (setq paragraph-ignore-fill-prefix t)\r
+  (make-local-variable 'indent-line-function)\r
+  (setq indent-line-function 'cperl-indent-line)\r
+  (make-local-variable 'require-final-newline)\r
+  (setq require-final-newline t)\r
+  (make-local-variable 'comment-start)\r
+  (setq comment-start "# ")\r
+  (make-local-variable 'comment-end)\r
+  (setq comment-end "")\r
+  (make-local-variable 'comment-column)\r
+  (setq comment-column cperl-comment-column)\r
+  (make-local-variable 'comment-start-skip)\r
+  (setq comment-start-skip "#+ *")\r
+  (make-local-variable 'defun-prompt-regexp)\r
+  (setq defun-prompt-regexp "^[ \t]*sub[ \t]+\\([^ \t\n{(;]+\\)\\([ \t]*([^()]*)[ \t]*\\)?[ \t]*")\r
+  (make-local-variable 'comment-indent-function)\r
+  (setq comment-indent-function 'cperl-comment-indent)\r
+  (make-local-variable 'parse-sexp-ignore-comments)\r
+  (setq parse-sexp-ignore-comments t)\r
+  (make-local-variable 'indent-region-function)\r
+  (setq indent-region-function 'cperl-indent-region)\r
+  ;;(setq auto-fill-function 'cperl-do-auto-fill) ; Need to switch on and off!\r
+  (make-local-variable 'imenu-create-index-function)\r
+  (setq imenu-create-index-function\r
+       (function cperl-imenu--create-perl-index))\r
+  (make-local-variable 'imenu-sort-function)\r
+  (setq imenu-sort-function nil)\r
+  (make-local-variable 'vc-header-alist)\r
+  (set 'vc-header-alist cperl-vc-header-alist) ; Avoid warning\r
+  (make-local-variable 'font-lock-defaults)\r
+  (setq        font-lock-defaults\r
+       (cond\r
+        ((string< emacs-version "19.30")\r
+         '(perl-font-lock-keywords-2))\r
+        ((string< emacs-version "19.33") ; Which one to use?\r
+         '((perl-font-lock-keywords\r
+            perl-font-lock-keywords-1\r
+            perl-font-lock-keywords-2)))\r
+        (t\r
+         '((cperl-load-font-lock-keywords\r
+            cperl-load-font-lock-keywords-1\r
+            cperl-load-font-lock-keywords-2)))))\r
+  (make-local-variable 'cperl-syntax-state)\r
+  (if cperl-use-syntax-table-text-property\r
+      (progn\r
+       (make-local-variable 'parse-sexp-lookup-properties)\r
+       ;; Do not introduce variable if not needed, we check it!\r
+       (set 'parse-sexp-lookup-properties t)\r
+       ;; Fix broken font-lock:\r
+       (or (boundp 'font-lock-unfontify-region-function)\r
+           (set 'font-lock-unfontify-region-function\r
+                'font-lock-default-unfontify-region))\r
+       (make-local-variable 'font-lock-unfontify-region-function)\r
+       (set 'font-lock-unfontify-region-function ; not present with old Emacs\r
+             'cperl-font-lock-unfontify-region-function)\r
+       (make-local-variable 'cperl-syntax-done-to)\r
+       ;; Another bug: unless font-lock-syntactic-keywords, font-lock\r
+       ;;  ignores syntax-table text-property.  (t) is a hack\r
+       ;;  to make font-lock think that font-lock-syntactic-keywords\r
+       ;;  are defined\r
+       (make-local-variable 'font-lock-syntactic-keywords)\r
+       (setq font-lock-syntactic-keywords\r
+             (if cperl-syntaxify-by-font-lock\r
+                 '(t (cperl-fontify-syntaxically))\r
+               '(t)))))\r
+  (make-local-variable 'cperl-old-style)\r
+  (if (boundp 'normal-auto-fill-function) ; 19.33 and later\r
+      (set (make-local-variable 'normal-auto-fill-function)\r
+          'cperl-do-auto-fill)       ; RMS has it as #'cperl-do-auto-fill ???\r
+    (or (fboundp 'cperl-old-auto-fill-mode)\r
+       (progn\r
+         (fset 'cperl-old-auto-fill-mode (symbol-function 'auto-fill-mode))\r
+         (defun auto-fill-mode (&optional arg)\r
+           (interactive "P")\r
+           (eval '(cperl-old-auto-fill-mode arg)) ; Avoid a warning\r
+           (and auto-fill-function (memq major-mode '(perl-mode cperl-mode))\r
+                (setq auto-fill-function 'cperl-do-auto-fill))))))\r
+  (if (cperl-enable-font-lock)\r
+      (if (cperl-val 'cperl-font-lock)\r
+         (progn (or cperl-faces-init (cperl-init-faces))\r
+                (font-lock-mode 1))))\r
+  (and (boundp 'msb-menu-cond)\r
+       (not cperl-msb-fixed)\r
+       (cperl-msb-fix))\r
+  (if (featurep 'easymenu)\r
+      (easy-menu-add cperl-menu))      ; A NOP in RMS Emacs.\r
+  (run-hooks 'cperl-mode-hook)\r
+  ;; After hooks since fontification will break this\r
+  (if cperl-pod-here-scan\r
+      (or cperl-syntaxify-by-font-lock\r
+       (progn (or cperl-faces-init (cperl-init-faces-weak))\r
+             (cperl-find-pods-heres)))))\r
+\f\r
+;; Fix for perldb - make default reasonable\r
+(defun cperl-db ()\r
+  (interactive)\r
+  (require 'gud)\r
+  (perldb (read-from-minibuffer "Run perldb (like this): "\r
+                               (if (consp gud-perldb-history)\r
+                                   (car gud-perldb-history)\r
+                                 (concat "perl " ;;(file-name-nondirectory\r
+                                         ;; I have problems\r
+                                         ;; in OS/2\r
+                                         ;; otherwise\r
+                                         (buffer-file-name)))\r
+                               nil nil\r
+                               '(gud-perldb-history . 1))))\r
+\f\r
+(defun cperl-msb-fix ()\r
+  ;; Adds perl files to msb menu, supposes that msb is already loaded\r
+  (setq cperl-msb-fixed t)\r
+  (let* ((l (length msb-menu-cond))\r
+        (last (nth (1- l) msb-menu-cond))\r
+        (precdr (nthcdr (- l 2) msb-menu-cond)) ; cdr of this is last\r
+        (handle (1- (nth 1 last))))\r
+    (setcdr precdr (list\r
+                   (list\r
+                    '(memq major-mode '(cperl-mode perl-mode))\r
+                    handle\r
+                    "Perl Files (%d)")\r
+                   last))))\r
+\f\r
+;; This is used by indent-for-comment\r
+;; to decide how much to indent a comment in CPerl code\r
+;; based on its context.  Do fallback if comment is found wrong.\r
+\r
+(defvar cperl-wrong-comment)\r
+(defvar cperl-st-cfence '(14))         ; Comment-fence\r
+(defvar cperl-st-sfence '(15))         ; String-fence\r
+(defvar cperl-st-punct '(1))\r
+(defvar cperl-st-word '(2))\r
+(defvar cperl-st-bra '(4 . ?\>))\r
+(defvar cperl-st-ket '(5 . ?\<))\r
+\r
+\r
+(defun cperl-comment-indent ()\r
+  (let ((p (point)) (c (current-column)) was phony)\r
+    (if (looking-at "^#") 0            ; Existing comment at bol stays there.\r
+      ;; Wrong comment found\r
+      (save-excursion\r
+       (setq was (cperl-to-comment-or-eol)\r
+             phony (eq (get-text-property (point) 'syntax-table)\r
+                       cperl-st-cfence))\r
+       (if phony\r
+           (progn\r
+             (re-search-forward "#\\|$") ; Hmm, what about embedded #?\r
+             (if (eq (preceding-char) ?\#)\r
+                 (forward-char -1))\r
+             (setq was nil)))\r
+       (if (= (point) p)\r
+           (progn\r
+             (skip-chars-backward " \t")\r
+             (max (1+ (current-column)) ; Else indent at comment column\r
+                  comment-column))\r
+         (if was nil\r
+           (insert comment-start)\r
+           (backward-char (length comment-start)))\r
+         (setq cperl-wrong-comment t)\r
+         (indent-to comment-column 1)  ; Indent minimum 1\r
+         c)))))                        ; except leave at least one space.\r
+\r
+;;;(defun cperl-comment-indent-fallback ()\r
+;;;  "Is called if the standard comment-search procedure fails.\r
+;;;Point is at start of real comment."\r
+;;;  (let ((c (current-column)) target cnt prevc)\r
+;;;    (if (= c comment-column) nil\r
+;;;      (setq cnt (skip-chars-backward "[ \t]"))\r
+;;;      (setq target (max (1+ (setq prevc\r
+;;;                         (current-column))) ; Else indent at comment column\r
+;;;               comment-column))\r
+;;;      (if (= c comment-column) nil\r
+;;;    (delete-backward-char cnt)\r
+;;;    (while (< prevc target)\r
+;;;      (insert "\t")\r
+;;;      (setq prevc (current-column)))\r
+;;;    (if (> prevc target) (progn (delete-char -1) (setq prevc (current-column))))\r
+;;;    (while (< prevc target)\r
+;;;      (insert " ")\r
+;;;      (setq prevc (current-column)))))))\r
+\r
+(defun cperl-indent-for-comment ()\r
+  "Substitute for `indent-for-comment' in CPerl."\r
+  (interactive)\r
+  (let (cperl-wrong-comment)\r
+    (indent-for-comment)\r
+    (if cperl-wrong-comment\r
+       (progn (cperl-to-comment-or-eol)\r
+              (forward-char (length comment-start))))))\r
+\r
+(defun cperl-comment-region (b e arg)\r
+  "Comment or uncomment each line in the region in CPerl mode.\r
+See `comment-region'."\r
+  (interactive "r\np")\r
+  (let ((comment-start "#"))\r
+    (comment-region b e arg)))\r
+\r
+(defun cperl-uncomment-region (b e arg)\r
+  "Uncomment or comment each line in the region in CPerl mode.\r
+See `comment-region'."\r
+  (interactive "r\np")\r
+  (let ((comment-start "#"))\r
+    (comment-region b e (- arg))))\r
+\r
+(defvar cperl-brace-recursing nil)\r
+\r
+(defun cperl-electric-brace (arg &optional only-before)\r
+  "Insert character and correct line's indentation.\r
+If ONLY-BEFORE and `cperl-auto-newline', will insert newline before the\r
+place (even in empty line), but not after.  If after \")\" and the inserted\r
+char is \"{\", insert extra newline before only if\r
+`cperl-extra-newline-before-brace'."\r
+  (interactive "P")\r
+  (let (insertpos\r
+       (other-end (if (and cperl-electric-parens-mark\r
+                           (cperl-mark-active)\r
+                           (< (mark) (point)))\r
+                      (mark)\r
+                    nil)))\r
+    (if (and other-end\r
+            (not cperl-brace-recursing)\r
+            (cperl-val 'cperl-electric-parens)\r
+            (>= (save-excursion (cperl-to-comment-or-eol) (point)) (point)))\r
+       ;; Need to insert a matching pair\r
+       (progn\r
+         (save-excursion\r
+           (setq insertpos (point-marker))\r
+           (goto-char other-end)\r
+           (setq last-command-char ?\{)\r
+           (cperl-electric-lbrace arg insertpos))\r
+         (forward-char 1))\r
+      ;; Check whether we close something "usual" with `}'\r
+      (if (and (eq last-command-char ?\})\r
+              (not\r
+               (condition-case nil\r
+                   (save-excursion\r
+                     (up-list (- (prefix-numeric-value arg)))\r
+                     ;;(cperl-after-block-p (point-min))\r
+                     (or (cperl-after-expr-p nil "{;)")\r
+                         ;; after sub, else, continue\r
+                         (cperl-after-block-p nil 'pre)))\r
+                 (error nil))))\r
+         ;; Just insert the guy\r
+         (self-insert-command (prefix-numeric-value arg))\r
+       (if (and (not arg)              ; No args, end (of empty line or auto)\r
+                (eolp)\r
+                (or (and (null only-before)\r
+                         (save-excursion\r
+                           (skip-chars-backward " \t")\r
+                           (bolp)))\r
+                    (and (eq last-command-char ?\{) ; Do not insert newline\r
+                         ;; if after ")" and `cperl-extra-newline-before-brace'\r
+                         ;; is nil, do not insert extra newline.\r
+                         (not cperl-extra-newline-before-brace)\r
+                         (save-excursion\r
+                           (skip-chars-backward " \t")\r
+                           (eq (preceding-char) ?\))))\r
+                    (if cperl-auto-newline\r
+                        (progn (cperl-indent-line) (newline) t) nil)))\r
+           (progn\r
+             (self-insert-command (prefix-numeric-value arg))\r
+             (cperl-indent-line)\r
+             (if cperl-auto-newline\r
+                 (setq insertpos (1- (point))))\r
+             (if (and cperl-auto-newline (null only-before))\r
+                 (progn\r
+                   (newline)\r
+                   (cperl-indent-line)))\r
+             (save-excursion\r
+               (if insertpos (progn (goto-char insertpos)\r
+                                    (search-forward (make-string\r
+                                                     1 last-command-char))\r
+                                    (setq insertpos (1- (point)))))\r
+               (delete-char -1))))\r
+       (if insertpos\r
+           (save-excursion\r
+             (goto-char insertpos)\r
+             (self-insert-command (prefix-numeric-value arg)))\r
+         (self-insert-command (prefix-numeric-value arg)))))))\r
+\r
+(defun cperl-electric-lbrace (arg &optional end)\r
+  "Insert character, correct line's indentation, correct quoting by space."\r
+  (interactive "P")\r
+  (let ((cperl-brace-recursing t)\r
+       (cperl-auto-newline cperl-auto-newline)\r
+       (other-end (or end\r
+                      (if (and cperl-electric-parens-mark\r
+                               (cperl-mark-active)\r
+                               (> (mark) (point)))\r
+                          (save-excursion\r
+                            (goto-char (mark))\r
+                            (point-marker))\r
+                        nil)))\r
+       pos after)\r
+    (and (cperl-val 'cperl-electric-lbrace-space)\r
+        (eq (preceding-char) ?$)\r
+        (save-excursion\r
+          (skip-chars-backward "$")\r
+          (looking-at "\\(\\$\\$\\)*\\$\\([^\\$]\\|$\\)"))\r
+        (insert ?\ ))\r
+    ;; Check whether we are in comment\r
+    (if (and\r
+        (save-excursion\r
+          (beginning-of-line)\r
+          (not (looking-at "[ \t]*#")))\r
+        (cperl-after-expr-p nil "{;)"))\r
+       nil\r
+      (setq cperl-auto-newline nil))\r
+    (cperl-electric-brace arg)\r
+    (and (cperl-val 'cperl-electric-parens)\r
+        (eq last-command-char ?{)\r
+        (memq last-command-char\r
+              (append cperl-electric-parens-string nil))\r
+        (or (if other-end (goto-char (marker-position other-end)))\r
+            t)\r
+        (setq last-command-char ?} pos (point))\r
+        (progn (cperl-electric-brace arg t)\r
+               (goto-char pos)))))\r
+\r
+(defun cperl-electric-paren (arg)\r
+  "Insert an opening parenthesis or a matching pair of parentheses.\r
+See `cperl-electric-parens'."\r
+  (interactive "P")\r
+  (let ((beg (save-excursion (beginning-of-line) (point)))\r
+       (other-end (if (and cperl-electric-parens-mark\r
+                           (cperl-mark-active)\r
+                           (> (mark) (point)))\r
+                      (save-excursion\r
+                        (goto-char (mark))\r
+                        (point-marker))\r
+                    nil)))\r
+    (if (and (cperl-val 'cperl-electric-parens)\r
+            (memq last-command-char\r
+                  (append cperl-electric-parens-string nil))\r
+            (>= (save-excursion (cperl-to-comment-or-eol) (point)) (point))\r
+            ;;(not (save-excursion (search-backward "#" beg t)))\r
+            (if (eq last-command-char ?<)\r
+                (progn\r
+                  (and abbrev-mode ; later it is too late, may be after `for'\r
+                       (expand-abbrev))\r
+                  (cperl-after-expr-p nil "{;(,:="))\r
+              1))\r
+       (progn\r
+         (self-insert-command (prefix-numeric-value arg))\r
+         (if other-end (goto-char (marker-position other-end)))\r
+         (insert (make-string\r
+                  (prefix-numeric-value arg)\r
+                  (cdr (assoc last-command-char '((?{ .?})\r
+                                                  (?[ . ?])\r
+                                                  (?( . ?))\r
+                                                  (?< . ?>))))))\r
+         (forward-char (- (prefix-numeric-value arg))))\r
+      (self-insert-command (prefix-numeric-value arg)))))\r
+\r
+(defun cperl-electric-rparen (arg)\r
+  "Insert a matching pair of parentheses if marking is active.\r
+If not, or if we are not at the end of marking range, would self-insert.\r
+Affected by `cperl-electric-parens'."\r
+  (interactive "P")\r
+  (let ((beg (save-excursion (beginning-of-line) (point)))\r
+       (other-end (if (and cperl-electric-parens-mark\r
+                           (cperl-val 'cperl-electric-parens)\r
+                           (memq last-command-char\r
+                                 (append cperl-electric-parens-string nil))\r
+                           (cperl-mark-active)\r
+                           (< (mark) (point)))\r
+                      (mark)\r
+                    nil))\r
+       p)\r
+    (if (and other-end\r
+            (cperl-val 'cperl-electric-parens)\r
+            (memq last-command-char '( ?\) ?\] ?\} ?\> ))\r
+            (>= (save-excursion (cperl-to-comment-or-eol) (point)) (point))\r
+            ;;(not (save-excursion (search-backward "#" beg t)))\r
+            )\r
+       (progn\r
+         (self-insert-command (prefix-numeric-value arg))\r
+         (setq p (point))\r
+         (if other-end (goto-char other-end))\r
+         (insert (make-string\r
+                  (prefix-numeric-value arg)\r
+                  (cdr (assoc last-command-char '((?\} . ?\{)\r
+                                                  (?\] . ?\[)\r
+                                                  (?\) . ?\()\r
+                                                  (?\> . ?\<))))))\r
+         (goto-char (1+ p)))\r
+      (self-insert-command (prefix-numeric-value arg)))))\r
+\r
+(defun cperl-electric-keyword ()\r
+  "Insert a construction appropriate after a keyword.\r
+Help message may be switched off by setting `cperl-message-electric-keyword'\r
+to nil."\r
+  (let ((beg (save-excursion (beginning-of-line) (point)))\r
+       (dollar (and (eq last-command-char ?$)\r
+                    (eq this-command 'self-insert-command)))\r
+       (delete (and (memq last-command-char '(?\ ?\n ?\t ?\f))\r
+                    (memq this-command '(self-insert-command newline))))\r
+       my do)\r
+    (and (save-excursion\r
+          (condition-case nil\r
+              (progn\r
+                (backward-sexp 1)\r
+                (setq do (looking-at "do\\>")))\r
+            (error nil))\r
+          (cperl-after-expr-p nil "{;:"))\r
+        (save-excursion\r
+          (not\r
+           (re-search-backward\r
+            "[#\"'`]\\|\\<q\\(\\|[wqxr]\\)\\>"\r
+            beg t)))\r
+        (save-excursion (or (not (re-search-backward "^=" nil t))\r
+                            (or\r
+                             (looking-at "=cut")\r
+                             (and cperl-use-syntax-table-text-property\r
+                                  (not (eq (get-text-property (point)\r
+                                                              'syntax-type)\r
+                                           'pod))))))\r
+        (save-excursion (forward-sexp -1) \r
+                        (not (memq (following-char) (append "$@%&*" nil))))\r
+        (progn\r
+          (and (eq (preceding-char) ?y)\r
+               (progn                  ; "foreachmy"\r
+                 (forward-char -2)\r
+                 (insert " ")\r
+                 (forward-char 2)\r
+                 (setq my t dollar t\r
+                       delete\r
+                       (memq this-command '(self-insert-command newline)))))\r
+          (and dollar (insert " $"))\r
+          (cperl-indent-line)\r
+          ;;(insert " () {\n}")\r
+          (cond\r
+           (cperl-extra-newline-before-brace\r
+            (insert (if do "\n" " ()\n"))\r
+            (insert "{")\r
+            (cperl-indent-line)\r
+            (insert "\n")\r
+            (cperl-indent-line)\r
+            (insert "\n}")\r
+            (and do (insert " while ();")))\r
+           (t\r
+            (insert (if do " {\n} while ();" " () {\n}"))))\r
+          (or (looking-at "[ \t]\\|$") (insert " "))\r
+          (cperl-indent-line)\r
+          (if dollar (progn (search-backward "$")\r
+                            (if my\r
+                                (forward-char 1)\r
+                              (delete-char 1)))\r
+            (search-backward ")")\r
+            (if (eq last-command-char ?\()\r
+                (progn                 ; Avoid "if (())"\r
+                  (delete-backward-char 1)\r
+                  (delete-backward-char -1))))\r
+          (if delete\r
+              (cperl-putback-char cperl-del-back-ch))\r
+          (if cperl-message-electric-keyword\r
+              (message "Precede char by C-q to avoid expansion"))))))\r
+\r
+(defun cperl-ensure-newlines (n &optional pos)\r
+  "Make sure there are N newlines after the point."\r
+  (or pos (setq pos (point)))\r
+  (if (looking-at "\n")\r
+      (forward-char 1)\r
+    (insert "\n"))\r
+  (if (> n 1)\r
+      (cperl-ensure-newlines (1- n) pos)\r
+    (goto-char pos)))\r
+\r
+(defun cperl-electric-pod ()\r
+  "Insert a POD chunk appropriate after a =POD directive."\r
+  (let ((delete (and (memq last-command-char '(?\ ?\n ?\t ?\f))\r
+                    (memq this-command '(self-insert-command newline))))\r
+       head1 notlast name p really-delete over)\r
+    (and (save-excursion\r
+          (forward-word -1)\r
+          (and\r
+           (eq (preceding-char) ?=)\r
+           (progn\r
+             (setq head1 (looking-at "head1\\>[ \t]*$"))\r
+             (setq over (and (looking-at "over\\>[ \t]*$")\r
+                             (not (looking-at "over[ \t]*\n\n\n*=item\\>"))))\r
+             (forward-char -1)\r
+             (bolp))\r
+           (or\r
+            (get-text-property (point) 'in-pod)\r
+            (cperl-after-expr-p nil "{;:")\r
+            (and (re-search-backward\r
+                  ;; "\\(\\`\n?\\|\n\n\\)=\\sw+"\r
+                  "\\(\\`\n?\\|^\n\\)=\\sw+"\r
+                  (point-min) t)\r
+                 (not (or\r
+                       (looking-at "=cut")\r
+                       (and cperl-use-syntax-table-text-property\r
+                            (not (eq (get-text-property (point) 'syntax-type)\r
+                                     'pod)))))))))\r
+        (progn\r
+          (save-excursion\r
+            (setq notlast (re-search-forward "^\n=" nil t)))\r
+          (or notlast\r
+              (progn\r
+                (insert "\n\n=cut")\r
+                (cperl-ensure-newlines 2)\r
+                (forward-word -2)\r
+                (if (and head1\r
+                         (not\r
+                          (save-excursion\r
+                            (forward-char -1)\r
+                            (re-search-backward "\\(\\`\n?\\|\n\n\\)=head1\\>"\r
+                                                nil t)))) ; Only one\r
+                    (progn\r
+                      (forward-word 1)\r
+                      (setq name (file-name-sans-extension\r
+                                  (file-name-nondirectory (buffer-file-name)))\r
+                            p (point))\r
+                      (insert " NAME\n\n" name\r
+                              " - \n\n=head1 SYNOPSIS\n\n\n\n"\r
+                              "=head1 DESCRIPTION")\r
+                      (cperl-ensure-newlines 4)\r
+                      (goto-char p)\r
+                      (forward-word 2)\r
+                      (end-of-line)\r
+                      (setq really-delete t))\r
+                  (forward-word 1))))\r
+          (if over\r
+              (progn\r
+                (setq p (point))\r
+                (insert "\n\n=item \n\n\n\n"\r
+                        "=back")\r
+                (cperl-ensure-newlines 2)\r
+                (goto-char p)\r
+                (forward-word 1)\r
+                (end-of-line)\r
+                (setq really-delete t)))\r
+          (if (and delete really-delete)\r
+              (cperl-putback-char cperl-del-back-ch))))))\r
+\r
+(defun cperl-electric-else ()\r
+  "Insert a construction appropriate after a keyword.\r
+Help message may be switched off by setting `cperl-message-electric-keyword'\r
+to nil."\r
+  (let ((beg (save-excursion (beginning-of-line) (point))))\r
+    (and (save-excursion\r
+          (backward-sexp 1)\r
+          (cperl-after-expr-p nil "{;:"))\r
+        (save-excursion\r
+          (not\r
+           (re-search-backward\r
+            "[#\"'`]\\|\\<q\\(\\|[wqxr]\\)\\>"\r
+            beg t)))\r
+        (save-excursion (or (not (re-search-backward "^=" nil t))\r
+                            (looking-at "=cut")\r
+                            (and cperl-use-syntax-table-text-property\r
+                                 (not (eq (get-text-property (point)\r
+                                                             'syntax-type)\r
+                                          'pod)))))\r
+        (progn\r
+          (cperl-indent-line)\r
+          ;;(insert " {\n\n}")\r
+          (cond\r
+           (cperl-extra-newline-before-brace\r
+            (insert "\n")\r
+            (insert "{")\r
+            (cperl-indent-line)\r
+            (insert "\n\n}"))\r
+           (t\r
+            (insert " {\n\n}")))\r
+          (or (looking-at "[ \t]\\|$") (insert " "))\r
+          (cperl-indent-line)\r
+          (forward-line -1)\r
+          (cperl-indent-line)\r
+          (cperl-putback-char cperl-del-back-ch)\r
+          (setq this-command 'cperl-electric-else)\r
+          (if cperl-message-electric-keyword\r
+              (message "Precede char by C-q to avoid expansion"))))))\r
+\r
+(defun cperl-linefeed ()\r
+  "Go to end of line, open a new line and indent appropriately.\r
+If in POD, insert appropriate lines."\r
+  (interactive)\r
+  (let ((beg (save-excursion (beginning-of-line) (point)))\r
+       (end (save-excursion (end-of-line) (point)))\r
+       (pos (point)) start over cut res)\r
+    (if (and                           ; Check if we need to split:\r
+                                       ; i.e., on a boundary and inside "{...}"\r
+        (save-excursion (cperl-to-comment-or-eol)\r
+                        (>= (point) pos)) ; Not in a comment\r
+        (or (save-excursion\r
+              (skip-chars-backward " \t" beg)\r
+              (forward-char -1)\r
+              (looking-at "[;{]"))     ; After { or ; + spaces\r
+            (looking-at "[ \t]*}")     ; Before }\r
+            (re-search-forward "\\=[ \t]*;" end t)) ; Before spaces + ;\r
+        (save-excursion\r
+          (and\r
+           (eq (car (parse-partial-sexp pos end -1)) -1)\r
+                                       ; Leave the level of parens\r
+           (looking-at "[,; \t]*\\($\\|#\\)") ; Comma to allow anon subr\r
+                                       ; Are at end\r
+           (cperl-after-block-p (point-min))\r
+           (progn\r
+             (backward-sexp 1)\r
+             (setq start (point-marker))\r
+             (<= start pos)))))        ; Redundant?  Are after the\r
+                                       ; start of parens group.\r
+       (progn\r
+         (skip-chars-backward " \t")\r
+         (or (memq (preceding-char) (append ";{" nil))\r
+             (insert ";"))\r
+         (insert "\n")\r
+         (forward-line -1)\r
+         (cperl-indent-line)\r
+         (goto-char start)\r
+         (or (looking-at "{[ \t]*$")   ; If there is a statement\r
+                                       ; before, move it to separate line\r
+             (progn\r
+               (forward-char 1)\r
+               (insert "\n")\r
+               (cperl-indent-line)))\r
+         (forward-line 1)              ; We are on the target line\r
+         (cperl-indent-line)\r
+         (beginning-of-line)\r
+         (or (looking-at "[ \t]*}[,; \t]*$") ; If there is a statement\r
+                                       ; after, move it to separate line\r
+             (progn\r
+               (end-of-line)\r
+               (search-backward "}" beg)\r
+               (skip-chars-backward " \t")\r
+               (or (memq (preceding-char) (append ";{" nil))\r
+                   (insert ";"))\r
+               (insert "\n")\r
+               (cperl-indent-line)\r
+               (forward-line -1)))\r
+         (forward-line -1)             ; We are on the line before target\r
+         (end-of-line)\r
+         (newline-and-indent))\r
+      (end-of-line)                    ; else - no splitting\r
+      (cond\r
+       ((and (looking-at "\n[ \t]*{$")\r
+            (save-excursion\r
+              (skip-chars-backward " \t")\r
+              (eq (preceding-char) ?\)))) ; Probably if () {} group\r
+                                       ; with an extra newline.\r
+       (forward-line 2)\r
+       (cperl-indent-line))\r
+       ((save-excursion                        ; In POD header\r
+         (forward-paragraph -1)\r
+         ;; (re-search-backward "\\(\\`\n?\\|\n\n\\)=head1\\b")\r
+         ;; We are after \n now, so look for the rest\r
+         (if (looking-at "\\(\\`\n?\\|\n\\)=\\sw+")\r
+             (progn\r
+               (setq cut (looking-at "\\(\\`\n?\\|\n\\)=cut\\>"))\r
+               (setq over (looking-at "\\(\\`\n?\\|\n\\)=over\\>"))\r
+               t)))\r
+       (if (and over\r
+                (progn\r
+                  (forward-paragraph -1)\r
+                  (forward-word 1)\r
+                  (setq pos (point))\r
+                  (setq cut (buffer-substring (point)\r
+                                              (save-excursion\r
+                                                (end-of-line)\r
+                                                (point))))\r
+                  (delete-char (- (save-excursion (end-of-line) (point))\r
+                                  (point)))\r
+                  (setq res (expand-abbrev))\r
+                  (save-excursion\r
+                    (goto-char pos)\r
+                    (insert cut))\r
+                  res))\r
+           nil\r
+         (cperl-ensure-newlines (if cut 2 4))\r
+         (forward-line 2)))\r
+       ((get-text-property (point) 'in-pod) ; In POD section\r
+       (cperl-ensure-newlines 4)\r
+       (forward-line 2))\r
+       ((looking-at "\n[ \t]*$")       ; Next line is empty - use it.\r
+        (forward-line 1)\r
+       (cperl-indent-line))\r
+       (t\r
+       (newline-and-indent))))))\r
+\r
+(defun cperl-electric-semi (arg)\r
+  "Insert character and correct line's indentation."\r
+  (interactive "P")\r
+  (if cperl-auto-newline\r
+      (cperl-electric-terminator arg)\r
+    (self-insert-command (prefix-numeric-value arg))\r
+    (if cperl-autoindent-on-semi\r
+       (cperl-indent-line))))\r
+\r
+(defun cperl-electric-terminator (arg)\r
+  "Insert character and correct line's indentation."\r
+  (interactive "P")\r
+  (let ((end (point))\r
+       (auto (and cperl-auto-newline\r
+                  (or (not (eq last-command-char ?:))\r
+                      cperl-auto-newline-after-colon)))\r
+       insertpos)\r
+    (if (and ;;(not arg)\r
+            (eolp)\r
+            (not (save-excursion\r
+                   (beginning-of-line)\r
+                   (skip-chars-forward " \t")\r
+                   (or\r
+                    ;; Ignore in comment lines\r
+                    (= (following-char) ?#)\r
+                    ;; Colon is special only after a label\r
+                    ;; So quickly rule out most other uses of colon\r
+                    ;; and do no indentation for them.\r
+                    (and (eq last-command-char ?:)\r
+                         (save-excursion\r
+                           (forward-word 1)\r
+                           (skip-chars-forward " \t")\r
+                           (and (< (point) end)\r
+                                (progn (goto-char (- end 1))\r
+                                       (not (looking-at ":"))))))\r
+                    (progn\r
+                      (beginning-of-defun)\r
+                      (let ((pps (parse-partial-sexp (point) end)))\r
+                        (or (nth 3 pps) (nth 4 pps) (nth 5 pps))))))))\r
+       (progn\r
+         (self-insert-command (prefix-numeric-value arg))\r
+         ;;(forward-char -1)\r
+         (if auto (setq insertpos (point-marker)))\r
+         ;;(forward-char 1)\r
+         (cperl-indent-line)\r
+         (if auto\r
+             (progn\r
+               (newline)\r
+               (cperl-indent-line)))\r
+         (save-excursion\r
+           (if insertpos (goto-char (1- (marker-position insertpos)))\r
+             (forward-char -1))\r
+           (delete-char 1))))\r
+    (if insertpos\r
+       (save-excursion\r
+         (goto-char insertpos)\r
+         (self-insert-command (prefix-numeric-value arg)))\r
+      (self-insert-command (prefix-numeric-value arg)))))\r
+\r
+(defun cperl-electric-backspace (arg)\r
+  "Backspace, or remove the whitespace around the point inserted by an electric\r
+key.  Will untabivy if `cperl-electric-backspace-untabify' is non-nil."\r
+  (interactive "p")\r
+  (if (and cperl-auto-newline\r
+          (memq last-command '(cperl-electric-semi\r
+                               cperl-electric-terminator\r
+                               cperl-electric-lbrace))\r
+          (memq (preceding-char) '(?\  ?\t ?\n)))\r
+      (let (p)\r
+       (if (eq last-command 'cperl-electric-lbrace)\r
+           (skip-chars-forward " \t\n"))\r
+       (setq p (point))\r
+       (skip-chars-backward " \t\n")\r
+       (delete-region (point) p))\r
+    (and (eq last-command 'cperl-electric-else)\r
+        ;; We are removing the whitespace *inside* cperl-electric-else\r
+        (setq this-command 'cperl-electric-else-really))\r
+    (if (and cperl-auto-newline\r
+            (eq last-command 'cperl-electric-else-really)\r
+            (memq (preceding-char) '(?\  ?\t ?\n)))\r
+       (let (p)\r
+         (skip-chars-forward " \t\n")\r
+         (setq p (point))\r
+         (skip-chars-backward " \t\n")\r
+         (delete-region (point) p))\r
+      (if cperl-electric-backspace-untabify\r
+         (backward-delete-char-untabify arg)\r
+       (delete-backward-char arg)))))\r
+\r
+(defun cperl-inside-parens-p ()\r
+  (condition-case ()\r
+      (save-excursion\r
+       (save-restriction\r
+         (narrow-to-region (point)\r
+                           (progn (beginning-of-defun) (point)))\r
+         (goto-char (point-max))\r
+         (= (char-after (or (scan-lists (point) -1 1) (point-min))) ?\()))\r
+    (error nil)))\r
+\f\r
+(defun cperl-indent-command (&optional whole-exp)\r
+  "Indent current line as Perl code, or in some cases insert a tab character.\r
+If `cperl-tab-always-indent' is non-nil (the default), always indent current\r
+line.  Otherwise, indent the current line only if point is at the left margin\r
+or in the line's indentation; otherwise insert a tab.\r
+\r
+A numeric argument, regardless of its value,\r
+means indent rigidly all the lines of the expression starting after point\r
+so that this line becomes properly indented.\r
+The relative indentation among the lines of the expression are preserved."\r
+  (interactive "P")\r
+  (cperl-update-syntaxification (point) (point))\r
+  (if whole-exp\r
+      ;; If arg, always indent this line as Perl\r
+      ;; and shift remaining lines of expression the same amount.\r
+      (let ((shift-amt (cperl-indent-line))\r
+           beg end)\r
+       (save-excursion\r
+         (if cperl-tab-always-indent\r
+             (beginning-of-line))\r
+         (setq beg (point))\r
+         (forward-sexp 1)\r
+         (setq end (point))\r
+         (goto-char beg)\r
+         (forward-line 1)\r
+         (setq beg (point)))\r
+       (if (and shift-amt (> end beg))\r
+           (indent-code-rigidly beg end shift-amt "#")))\r
+    (if (and (not cperl-tab-always-indent)\r
+            (save-excursion\r
+              (skip-chars-backward " \t")\r
+              (not (bolp))))\r
+       (insert-tab)\r
+      (cperl-indent-line))))\r
+\r
+(defun cperl-indent-line (&optional parse-data)\r
+  "Indent current line as Perl code.\r
+Return the amount the indentation changed by."\r
+  (let ((case-fold-search nil)\r
+       (pos (- (point-max) (point)))\r
+       indent i beg shift-amt)\r
+    (setq indent (cperl-calculate-indent parse-data)\r
+         i indent)\r
+    (beginning-of-line)\r
+    (setq beg (point))\r
+    (cond ((or (eq indent nil) (eq indent t))\r
+          (setq indent (current-indentation) i nil))\r
+         ;;((eq indent t)    ; Never?\r
+         ;; (setq indent (cperl-calculate-indent-within-comment)))\r
+         ;;((looking-at "[ \t]*#")\r
+         ;; (setq indent 0))\r
+         (t\r
+          (skip-chars-forward " \t")\r
+          (if (listp indent) (setq indent (car indent)))\r
+          (cond ((looking-at "[A-Za-z_][A-Za-z_0-9]*:[^:]")\r
+                 (and (> indent 0)\r
+                      (setq indent (max cperl-min-label-indent\r
+                                        (+ indent cperl-label-offset)))))\r
+                ((= (following-char) ?})\r
+                 (setq indent (- indent cperl-indent-level)))\r
+                ((memq (following-char) '(?\) ?\])) ; To line up with opening paren.\r
+                 (setq indent (+ indent cperl-close-paren-offset)))\r
+                ((= (following-char) ?{)\r
+                 (setq indent (+ indent cperl-brace-offset))))))\r
+    (skip-chars-forward " \t")\r
+    (setq shift-amt (and i (- indent (current-column))))\r
+    (if (or (not shift-amt)\r
+           (zerop shift-amt))\r
+       (if (> (- (point-max) pos) (point))\r
+           (goto-char (- (point-max) pos)))\r
+      (delete-region beg (point))\r
+      (indent-to indent)\r
+      ;; If initial point was within line's indentation,\r
+      ;; position after the indentation.  Else stay at same point in text.\r
+      (if (> (- (point-max) pos) (point))\r
+         (goto-char (- (point-max) pos))))\r
+    shift-amt))\r
+\r
+(defun cperl-after-label ()\r
+  ;; Returns true if the point is after label.  Does not do save-excursion.\r
+  (and (eq (preceding-char) ?:)\r
+       (memq (char-syntax (char-after (- (point) 2)))\r
+            '(?w ?_))\r
+       (progn\r
+        (backward-sexp)\r
+        (looking-at "[a-zA-Z_][a-zA-Z0-9_]*:[^:]"))))\r
+\r
+(defun cperl-get-state (&optional parse-start start-state)\r
+  ;; returns list (START STATE DEPTH PRESTART),\r
+  ;; START is a good place to start parsing, or equal to\r
+  ;; PARSE-START if preset,\r
+  ;; STATE is what is returned by `parse-partial-sexp'.\r
+  ;; DEPTH is true is we are immediately after end of block\r
+  ;; which contains START.\r
+  ;; PRESTART is the position basing on which START was found.\r
+  (save-excursion\r
+    (let ((start-point (point)) depth state start prestart)\r
+      (if (and parse-start\r
+              (<= parse-start start-point))\r
+         (goto-char parse-start)\r
+       (beginning-of-defun)\r
+       (setq start-state nil))\r
+      (setq prestart (point))\r
+      (if start-state nil\r
+       ;; Try to go out, if sub is not on the outermost level\r
+       (while (< (point) start-point)\r
+         (setq start (point) parse-start start depth nil\r
+               state (parse-partial-sexp start start-point -1))\r
+         (if (> (car state) -1) nil\r
+           ;; The current line could start like }}}, so the indentation\r
+           ;; corresponds to a different level than what we reached\r
+           (setq depth t)\r
+           (beginning-of-line 2)))     ; Go to the next line.\r
+       (if start (goto-char start)))   ; Not at the start of file\r
+      (setq start (point))\r
+      (or state (setq state (parse-partial-sexp start start-point -1 nil start-state)))\r
+      (list start state depth prestart))))\r
+\r
+(defun cperl-block-p ()                   ; Do not C-M-q !  One string contains ";" !\r
+  ;; Positions is before ?\{.  Checks whether it starts a block.\r
+  ;; No save-excursion!\r
+  (cperl-backward-to-noncomment (point-min))\r
+  (or (memq (preceding-char) (append ";){}$@&%\C-@" nil)) ; Or label!  \C-@ at bobp\r
+                                       ; Label may be mixed up with `$blah :'\r
+      (save-excursion (cperl-after-label))\r
+      (and (memq (char-syntax (preceding-char)) '(?w ?_))\r
+          (progn\r
+            (backward-sexp)\r
+            ;; Need take into account `bless', `return', `tr',...\r
+            (or (and (looking-at "[a-zA-Z0-9_:]+[ \t\n\f]*[{#]") ; Method call syntax\r
+                     (not (looking-at "\\(bless\\|return\\|q[wqrx]?\\|tr\\|[smy]\\)\\>")))\r
+                (progn\r
+                  (skip-chars-backward " \t\n\f")\r
+                  (and (memq (char-syntax (preceding-char)) '(?w ?_))\r
+                       (progn\r
+                         (backward-sexp)\r
+                         (looking-at\r
+                          "sub[ \t]+[a-zA-Z0-9_:]+[ \t\n\f]*\\(([^()]*)[ \t\n\f]*\\)?[#{]")))))))))\r
+\r
+(defvar cperl-look-for-prop '((pod in-pod) (here-doc-delim here-doc-group)))\r
+\r
+(defun cperl-calculate-indent (&optional parse-data) ; was parse-start\r
+  "Return appropriate indentation for current line as Perl code.\r
+In usual case returns an integer: the column to indent to.\r
+Returns nil if line starts inside a string, t if in a comment.\r
+\r
+Will not correct the indentation for labels, but will correct it for braces\r
+and closing parentheses and brackets."\r
+  (cperl-update-syntaxification (point) (point))\r
+  (save-excursion\r
+    (if (or\r
+        (and (memq (get-text-property (point) 'syntax-type)\r
+                   '(pod here-doc here-doc-delim format))\r
+             (not (get-text-property (point) 'indentable)))\r
+        ;; before start of POD - whitespace found since do not have 'pod!\r
+        (and (looking-at "[ \t]*\n=")\r
+             (error "Spaces before POD section!"))\r
+        (and (not cperl-indent-left-aligned-comments)\r
+             (looking-at "^#")))\r
+       nil\r
+      (beginning-of-line)\r
+      (let ((indent-point (point))\r
+           (char-after (save-excursion\r
+                         (skip-chars-forward " \t")\r
+                         (following-char)))\r
+           (in-pod (get-text-property (point) 'in-pod))\r
+           (pre-indent-point (point))\r
+           p prop look-prop is-block delim)\r
+       (cond\r
+        (in-pod\r
+         ;; In the verbatim part, probably code example.  What to do???\r
+         )\r
+        (t\r
+         (save-excursion\r
+           ;; Not in POD\r
+           (cperl-backward-to-noncomment nil)\r
+           (setq p (max (point-min) (1- (point)))\r
+                 prop (get-text-property p 'syntax-type)\r
+                 look-prop (or (nth 1 (assoc prop cperl-look-for-prop))\r
+                               'syntax-type))\r
+           (if (memq prop '(pod here-doc format here-doc-delim))\r
+               (progn\r
+                 (goto-char (or (previous-single-property-change p look-prop)\r
+                                (point-min)))\r
+                 (beginning-of-line)\r
+                 (setq pre-indent-point (point)))))))\r
+       (goto-char pre-indent-point)\r
+       (let* ((case-fold-search nil)\r
+              (s-s (cperl-get-state (car parse-data) (nth 1 parse-data)))\r
+              (start (or (nth 2 parse-data)\r
+                         (nth 0 s-s)))\r
+              (state (nth 1 s-s))\r
+              (containing-sexp (car (cdr state)))\r
+              old-indent)\r
+         (if (and\r
+              ;;containing-sexp                ;; We are buggy at toplevel :-(\r
+              parse-data)\r
+             (progn\r
+               (setcar parse-data pre-indent-point)\r
+               (setcar (cdr parse-data) state)\r
+               (or (nth 2 parse-data)\r
+                   (setcar (cddr parse-data) start))\r
+               ;; Before this point: end of statement\r
+               (setq old-indent (nth 3 parse-data))))\r
+         (cond ((get-text-property (point) 'indentable)\r
+                ;; indent to just after the surrounding open,\r
+                ;; skip blanks if we do not close the expression.\r
+                (goto-char (1+ (previous-single-property-change (point) 'indentable)))\r
+                (or (memq char-after (append ")]}" nil))\r
+                    (looking-at "[ \t]*\\(#\\|$\\)")\r
+                    (skip-chars-forward " \t"))\r
+                (current-column))\r
+               ((or (nth 3 state) (nth 4 state))\r
+                ;; return nil or t if should not change this line\r
+                (nth 4 state))\r
+               ;; XXXX Do we need to special-case this?\r
+               ((null containing-sexp)\r
+                ;; Line is at top level.  May be data or function definition,\r
+                ;; or may be function argument declaration.\r
+                ;; Indent like the previous top level line\r
+                ;; unless that ends in a closeparen without semicolon,\r
+                ;; in which case this line is the first argument decl.\r
+                (skip-chars-forward " \t")\r
+                (+ (save-excursion\r
+                     (goto-char start)\r
+                     (- (current-indentation)\r
+                        (if (nth 2 s-s) cperl-indent-level 0)))\r
+                   (if (= char-after ?{) cperl-continued-brace-offset 0)\r
+                   (progn\r
+                     (cperl-backward-to-noncomment (or old-indent (point-min)))\r
+                     ;; Look at previous line that's at column 0\r
+                     ;; to determine whether we are in top-level decls\r
+                     ;; or function's arg decls.  Set basic-indent accordingly.\r
+                     ;; Now add a little if this is a continuation line.\r
+                     (if (or (bobp)\r
+                             (eq (point) old-indent) ; old-indent was at comment\r
+                             (eq (preceding-char) ?\;)\r
+                             ;;  Had ?\) too\r
+                             (and (eq (preceding-char) ?\})\r
+                                  (cperl-after-block-and-statement-beg\r
+                                   (point-min))) ; Was start - too close\r
+                             (memq char-after (append ")]}" nil))\r
+                             (and (eq (preceding-char) ?\:) ; label\r
+                                  (progn\r
+                                    (forward-sexp -1)\r
+                                    (skip-chars-backward " \t")\r
+                                    (looking-at "[ \t]*[a-zA-Z_][a-zA-Z_0-9]*[ \t]*:")))\r
+                             (get-text-property (point) 'first-format-line))\r
+                         (progn\r
+                           (if (and parse-data\r
+                                    (not (eq char-after ?\C-j)))\r
+                               (setcdr (cddr parse-data)\r
+                                       (list pre-indent-point)))\r
+                           0)\r
+                       cperl-continued-statement-offset))))\r
+               ((not\r
+                 (or (setq is-block\r
+                           (and (setq delim (= (char-after containing-sexp) ?{))\r
+                                (save-excursion ; Is it a hash?\r
+                                  (goto-char containing-sexp)\r
+                                  (cperl-block-p))))\r
+                     cperl-indent-parens-as-block))\r
+                ;; group is an expression, not a block:\r
+                ;; indent to just after the surrounding open parens,\r
+                ;; skip blanks if we do not close the expression.\r
+                (goto-char (1+ containing-sexp))\r
+                (or (memq char-after\r
+                          (append (if delim "}" ")]}") nil))\r
+                    (looking-at "[ \t]*\\(#\\|$\\)")\r
+                    (skip-chars-forward " \t"))\r
+                (+ (current-column)\r
+                   (if (and delim\r
+                            (eq char-after ?\}))\r
+                       ;; Correct indentation of trailing ?\}\r
+                       (+ cperl-indent-level cperl-close-paren-offset)\r
+                     0)))\r
+;;;          ((and (/= (char-after containing-sexp) ?{)\r
+;;;                (not cperl-indent-parens-as-block))\r
+;;;           ;; line is expression, not statement:\r
+;;;           ;; indent to just after the surrounding open,\r
+;;;           ;; skip blanks if we do not close the expression.\r
+;;;           (goto-char (1+ containing-sexp))\r
+;;;           (or (memq char-after (append ")]}" nil))\r
+;;;               (looking-at "[ \t]*\\(#\\|$\\)")\r
+;;;               (skip-chars-forward " \t"))\r
+;;;           (current-column))\r
+;;;          ((progn\r
+;;;             ;; Containing-expr starts with \{.  Check whether it is a hash.\r
+;;;             (goto-char containing-sexp)\r
+;;;             (and (not (cperl-block-p))\r
+;;;                  (not cperl-indent-parens-as-block)))\r
+;;;           (goto-char (1+ containing-sexp))\r
+;;;           (or (eq char-after ?\})\r
+;;;               (looking-at "[ \t]*\\(#\\|$\\)")\r
+;;;               (skip-chars-forward " \t"))\r
+;;;           (+ (current-column)      ; Correct indentation of trailing ?\}\r
+;;;              (if (eq char-after ?\}) (+ cperl-indent-level\r
+;;;                                         cperl-close-paren-offset)\r
+;;;                0)))\r
+               (t\r
+                ;; Statement level.  Is it a continuation or a new statement?\r
+                ;; Find previous non-comment character.\r
+                (goto-char pre-indent-point)\r
+                (cperl-backward-to-noncomment containing-sexp)\r
+                ;; Back up over label lines, since they don't\r
+                ;; affect whether our line is a continuation.\r
+                ;; (Had \, too)\r
+                (while ;;(or (eq (preceding-char) ?\,)\r
+                    (and (eq (preceding-char) ?:)\r
+                         (or ;;(eq (char-after (- (point) 2)) ?\') ; ????\r
+                          (memq (char-syntax (char-after (- (point) 2)))\r
+                                '(?w ?_))))\r
+                  ;;)\r
+                  (if (eq (preceding-char) ?\,)\r
+                      ;; Will go to beginning of line, essentially.\r
+                      ;; Will ignore embedded sexpr XXXX.\r
+                      (cperl-backward-to-start-of-continued-exp containing-sexp))\r
+                  (beginning-of-line)\r
+                  (cperl-backward-to-noncomment containing-sexp))\r
+                ;; Now we get the answer.\r
+                (if (not (or (eq (1- (point)) containing-sexp)\r
+                             (memq (preceding-char)\r
+                                   (append (if is-block " ;{" " ,;{") '(nil)))\r
+                             (and (eq (preceding-char) ?\})\r
+                                  (cperl-after-block-and-statement-beg\r
+                                   containing-sexp))\r
+                             (get-text-property (point) 'first-format-line)))\r
+                    ;; This line is continuation of preceding line's statement;\r
+                    ;; indent  `cperl-continued-statement-offset'  more than the\r
+                    ;; previous line of the statement.\r
+                    ;;\r
+                    ;; There might be a label on this line, just\r
+                    ;; consider it bad style and ignore it.\r
+                    (progn\r
+                      (cperl-backward-to-start-of-continued-exp containing-sexp)\r
+                      (+ (if (memq char-after (append "}])" nil))\r
+                             0         ; Closing parenth\r
+                           cperl-continued-statement-offset)\r
+                         (if (or is-block\r
+                                 (not delim)\r
+                                 (not (eq char-after ?\})))\r
+                             0\r
+                           ;; Now it is a hash reference\r
+                           (+ cperl-indent-level cperl-close-paren-offset))\r
+                         (if (looking-at "\\w+[ \t]*:")\r
+                             (if (> (current-indentation) cperl-min-label-indent)\r
+                                 (- (current-indentation) cperl-label-offset)\r
+                               ;; Do not move `parse-data', this should\r
+                               ;; be quick anyway (this comment comes\r
+                               ;; from different location):\r
+                               (cperl-calculate-indent))\r
+                           (current-column))\r
+                         (if (eq char-after ?\{)\r
+                             cperl-continued-brace-offset 0)))\r
+                  ;; This line starts a new statement.\r
+                  ;; Position following last unclosed open.\r
+                  (goto-char containing-sexp)\r
+                  ;; Is line first statement after an open-brace?\r
+                  (or\r
+                   ;; If no, find that first statement and indent like\r
+                   ;; it.  If the first statement begins with label, do\r
+                   ;; not believe when the indentation of the label is too\r
+                   ;; small.\r
+                   (save-excursion\r
+                     (forward-char 1)\r
+                     (setq old-indent (current-indentation))\r
+                     (let ((colon-line-end 0))\r
+                       (while\r
+                           (progn (skip-chars-forward " \t\n")\r
+                                  (looking-at "#\\|[a-zA-Z0-9_$]*:[^:]\\|=[a-zA-Z]"))\r
+                         ;; Skip over comments and labels following openbrace.\r
+                         (cond ((= (following-char) ?\#)\r
+                                (forward-line 1))\r
+                               ((= (following-char) ?\=)\r
+                                (goto-char\r
+                                 (or (next-single-property-change (point) 'in-pod)\r
+                                     (point-max)))) ; do not loop if no syntaxification\r
+                               ;; label:\r
+                               (t\r
+                                (save-excursion (end-of-line)\r
+                                                (setq colon-line-end (point)))\r
+                                (search-forward ":"))))\r
+                       ;; The first following code counts\r
+                       ;; if it is before the line we want to indent.\r
+                       (and (< (point) indent-point)\r
+                            (if (> colon-line-end (point)) ; After label\r
+                                (if (> (current-indentation)\r
+                                       cperl-min-label-indent)\r
+                                    (- (current-indentation) cperl-label-offset)\r
+                                  ;; Do not believe: `max' is involved\r
+                                  (+ old-indent cperl-indent-level))\r
+                              (current-column)))))\r
+                   ;; If no previous statement,\r
+                   ;; indent it relative to line brace is on.\r
+                   ;; For open brace in column zero, don't let statement\r
+                   ;; start there too.  If cperl-indent-level is zero,\r
+                   ;; use cperl-brace-offset + cperl-continued-statement-offset instead.\r
+                   ;; For open-braces not the first thing in a line,\r
+                   ;; add in cperl-brace-imaginary-offset.\r
+\r
+                   ;; If first thing on a line:  ?????\r
+                   (+ (if (and (bolp) (zerop cperl-indent-level))\r
+                          (+ cperl-brace-offset cperl-continued-statement-offset)\r
+                        cperl-indent-level)\r
+                      (if (or is-block\r
+                              (not delim)\r
+                              (not (eq char-after ?\})))\r
+                          0\r
+                        ;; Now it is a hash reference\r
+                        (+ cperl-indent-level cperl-close-paren-offset))\r
+                      ;; Move back over whitespace before the openbrace.\r
+                      ;; If openbrace is not first nonwhite thing on the line,\r
+                      ;; add the cperl-brace-imaginary-offset.\r
+                      (progn (skip-chars-backward " \t")\r
+                             (if (bolp) 0 cperl-brace-imaginary-offset))\r
+                      ;; If the openbrace is preceded by a parenthesized exp,\r
+                      ;; move to the beginning of that;\r
+                      ;; possibly a different line\r
+                      (progn\r
+                        (if (eq (preceding-char) ?\))\r
+                            (forward-sexp -1))\r
+                        ;; In the case it starts a subroutine, indent with\r
+                        ;; respect to `sub', not with respect to the\r
+                        ;; first thing on the line, say in the case of\r
+                        ;; anonymous sub in a hash.\r
+                        ;;\r
+                        (skip-chars-backward " \t")\r
+                        (if (and (eq (preceding-char) ?b)\r
+                                 (progn\r
+                                   (forward-sexp -1)\r
+                                   (looking-at "sub\\>"))\r
+                                 (setq old-indent\r
+                                       (nth 1\r
+                                            (parse-partial-sexp\r
+                                             (save-excursion (beginning-of-line) (point))\r
+                                             (point)))))\r
+                            (progn (goto-char (1+ old-indent))\r
+                                   (skip-chars-forward " \t")\r
+                                   (current-column))\r
+                          ;; Get initial indentation of the line we are on.\r
+                          ;; If line starts with label, calculate label indentation\r
+                          (if (save-excursion\r
+                                (beginning-of-line)\r
+                                (looking-at "[ \t]*[a-zA-Z_][a-zA-Z_0-9]*:[^:]"))\r
+                              (if (> (current-indentation) cperl-min-label-indent)\r
+                                  (- (current-indentation) cperl-label-offset)\r
+                                ;; Do not move `parse-data', this should\r
+                                ;; be quick anyway:\r
+                                (cperl-calculate-indent))\r
+                            (current-indentation))))))))))))))\r
+\r
+(defvar cperl-indent-alist\r
+  '((string nil)\r
+    (comment nil)\r
+    (toplevel 0)\r
+    (toplevel-after-parenth 2)\r
+    (toplevel-continued 2)\r
+    (expression 1))\r
+  "Alist of indentation rules for CPerl mode.\r
+The values mean:\r
+  nil: do not indent;\r
+  number: add this amount of indentation.\r
+\r
+Not finished, not used.")\r
+\r
+(defun cperl-where-am-i (&optional parse-start start-state)\r
+  ;; Unfinished\r
+  "Return a list of lists ((TYPE POS)...) of good points before the point.\r
+POS may be nil if it is hard to find, say, when TYPE is `string' or `comment'.\r
+\r
+Not finished, not used."\r
+  (save-excursion\r
+    (let* ((start-point (point))\r
+          (s-s (cperl-get-state))\r
+          (start (nth 0 s-s))\r
+          (state (nth 1 s-s))\r
+          (prestart (nth 3 s-s))\r
+          (containing-sexp (car (cdr state)))\r
+          (case-fold-search nil)\r
+          (res (list (list 'parse-start start) (list 'parse-prestart prestart))))\r
+      (cond ((nth 3 state)             ; In string\r
+            (setq res (cons (list 'string nil (nth 3 state)) res))) ; What started string\r
+           ((nth 4 state)              ; In comment\r
+            (setq res (cons '(comment) res)))\r
+           ((null containing-sexp)\r
+            ;; Line is at top level.\r
+            ;; Indent like the previous top level line\r
+            ;; unless that ends in a closeparen without semicolon,\r
+            ;; in which case this line is the first argument decl.\r
+            (cperl-backward-to-noncomment (or parse-start (point-min)))\r
+            ;;(skip-chars-backward " \t\f\n")\r
+            (cond\r
+             ((or (bobp)\r
+                  (memq (preceding-char) (append ";}" nil)))\r
+              (setq res (cons (list 'toplevel start) res)))\r
+             ((eq (preceding-char) ?\) )\r
+              (setq res (cons (list 'toplevel-after-parenth start) res)))\r
+             (t\r
+              (setq res (cons (list 'toplevel-continued start) res)))))\r
+           ((/= (char-after containing-sexp) ?{)\r
+            ;; line is expression, not statement:\r
+            ;; indent to just after the surrounding open.\r
+            ;; skip blanks if we do not close the expression.\r
+            (setq res (cons (list 'expression-blanks\r
+                                  (progn\r
+                                    (goto-char (1+ containing-sexp))\r
+                                    (or (looking-at "[ \t]*\\(#\\|$\\)")\r
+                                        (skip-chars-forward " \t"))\r
+                                    (point)))\r
+                            (cons (list 'expression containing-sexp) res))))\r
+           ((progn\r
+              ;; Containing-expr starts with \{.  Check whether it is a hash.\r
+              (goto-char containing-sexp)\r
+              (not (cperl-block-p)))\r
+            (setq res (cons (list 'expression-blanks\r
+                                  (progn\r
+                                    (goto-char (1+ containing-sexp))\r
+                                    (or (looking-at "[ \t]*\\(#\\|$\\)")\r
+                                        (skip-chars-forward " \t"))\r
+                                    (point)))\r
+                            (cons (list 'expression containing-sexp) res))))\r
+           (t\r
+            ;; Statement level.\r
+            (setq res (cons (list 'in-block containing-sexp) res))\r
+            ;; Is it a continuation or a new statement?\r
+            ;; Find previous non-comment character.\r
+            (cperl-backward-to-noncomment containing-sexp)\r
+            ;; Back up over label lines, since they don't\r
+            ;; affect whether our line is a continuation.\r
+            ;; Back up comma-delimited lines too ?????\r
+            (while (or (eq (preceding-char) ?\,)\r
+                       (save-excursion (cperl-after-label)))\r
+              (if (eq (preceding-char) ?\,)\r
+                  ;; Will go to beginning of line, essentially\r
+                  ;; Will ignore embedded sexpr XXXX.\r
+                  (cperl-backward-to-start-of-continued-exp containing-sexp))\r
+              (beginning-of-line)\r
+              (cperl-backward-to-noncomment containing-sexp))\r
+            ;; Now we get the answer.\r
+            (if (not (memq (preceding-char) (append ";}{" '(nil)))) ; Was ?\,\r
+                ;; This line is continuation of preceding line's statement.\r
+                (list (list 'statement-continued containing-sexp))\r
+              ;; This line starts a new statement.\r
+              ;; Position following last unclosed open.\r
+              (goto-char containing-sexp)\r
+              ;; Is line first statement after an open-brace?\r
+              (or\r
+               ;; If no, find that first statement and indent like\r
+               ;; it.  If the first statement begins with label, do\r
+               ;; not believe when the indentation of the label is too\r
+               ;; small.\r
+               (save-excursion\r
+                 (forward-char 1)\r
+                 (let ((colon-line-end 0))\r
+                   (while (progn (skip-chars-forward " \t\n" start-point)\r
+                                 (and (< (point) start-point)\r
+                                      (looking-at\r
+                                       "#\\|[a-zA-Z_][a-zA-Z0-9_]*:[^:]")))\r
+                     ;; Skip over comments and labels following openbrace.\r
+                     (cond ((= (following-char) ?\#)\r
+                            ;;(forward-line 1)\r
+                            (end-of-line))\r
+                           ;; label:\r
+                           (t\r
+                            (save-excursion (end-of-line)\r
+                                            (setq colon-line-end (point)))\r
+                            (search-forward ":"))))\r
+                   ;; Now at the point, after label, or at start\r
+                   ;; of first statement in the block.\r
+                   (and (< (point) start-point)\r
+                        (if (> colon-line-end (point))\r
+                            ;; Before statement after label\r
+                            (if (> (current-indentation)\r
+                                   cperl-min-label-indent)\r
+                                (list (list 'label-in-block (point)))\r
+                              ;; Do not believe: `max' is involved\r
+                              (list\r
+                               (list 'label-in-block-min-indent (point))))\r
+                          ;; Before statement\r
+                          (list 'statement-in-block (point))))))\r
+               ;; If no previous statement,\r
+               ;; indent it relative to line brace is on.\r
+               ;; For open brace in column zero, don't let statement\r
+               ;; start there too.  If cperl-indent-level is zero,\r
+               ;; use cperl-brace-offset + cperl-continued-statement-offset instead.\r
+               ;; For open-braces not the first thing in a line,\r
+               ;; add in cperl-brace-imaginary-offset.\r
+\r
+               ;; If first thing on a line:  ?????\r
+               (+ (if (and (bolp) (zerop cperl-indent-level))\r
+                      (+ cperl-brace-offset cperl-continued-statement-offset)\r
+                    cperl-indent-level)\r
+                  ;; Move back over whitespace before the openbrace.\r
+                  ;; If openbrace is not first nonwhite thing on the line,\r
+                  ;; add the cperl-brace-imaginary-offset.\r
+                  (progn (skip-chars-backward " \t")\r
+                         (if (bolp) 0 cperl-brace-imaginary-offset))\r
+                  ;; If the openbrace is preceded by a parenthesized exp,\r
+                  ;; move to the beginning of that;\r
+                  ;; possibly a different line\r
+                  (progn\r
+                    (if (eq (preceding-char) ?\))\r
+                        (forward-sexp -1))\r
+                    ;; Get initial indentation of the line we are on.\r
+                    ;; If line starts with label, calculate label indentation\r
+                    (if (save-excursion\r
+                          (beginning-of-line)\r
+                          (looking-at "[ \t]*[a-zA-Z_][a-zA-Z_0-9]*:[^:]"))\r
+                        (if (> (current-indentation) cperl-min-label-indent)\r
+                            (- (current-indentation) cperl-label-offset)\r
+                          (cperl-calculate-indent))\r
+                      (current-indentation))))))))\r
+      res)))\r
+\r
+(defun cperl-calculate-indent-within-comment ()\r
+  "Return the indentation amount for line, assuming that\r
+the current line is to be regarded as part of a block comment."\r
+  (let (end star-start)\r
+    (save-excursion\r
+      (beginning-of-line)\r
+      (skip-chars-forward " \t")\r
+      (setq end (point))\r
+      (and (= (following-char) ?#)\r
+          (forward-line -1)\r
+          (cperl-to-comment-or-eol)\r
+          (setq end (point)))\r
+      (goto-char end)\r
+      (current-column))))\r
+\r
+\r
+(defun cperl-to-comment-or-eol ()\r
+  "Go to position before comment on the current line, or to end of line.\r
+Returns true if comment is found."\r
+  (let (state stop-in cpoint (lim (progn (end-of-line) (point))))\r
+    (beginning-of-line)\r
+    (if (or\r
+        (eq (get-text-property (point) 'syntax-type) 'pod)\r
+        (re-search-forward "\\=[ \t]*\\(#\\|$\\)" lim t))\r
+       (if (eq (preceding-char) ?\#) (progn (backward-char 1) t))\r
+      ;; Else\r
+      (while (not stop-in)\r
+       (setq state (parse-partial-sexp (point) lim nil nil nil t))\r
+                                       ; stop at comment\r
+       ;; If fails (beginning-of-line inside sexp), then contains not-comment\r
+       (if (nth 4 state)               ; After `#';\r
+                                       ; (nth 2 state) can be\r
+                                       ; beginning of m,s,qq and so\r
+                                       ; on\r
+           (if (nth 2 state)\r
+               (progn\r
+                 (setq cpoint (point))\r
+                 (goto-char (nth 2 state))\r
+                 (cond\r
+                  ((looking-at "\\(s\\|tr\\)\\>")\r
+                   (or (re-search-forward\r
+                        "\\=\\w+[ \t]*#\\([^\n\\\\#]\\|\\\\[\\\\#]\\)*#\\([^\n\\\\#]\\|\\\\[\\\\#]\\)*"\r
+                        lim 'move)\r
+                       (setq stop-in t)))\r
+                  ((looking-at "\\(m\\|q\\([qxwr]\\)?\\)\\>")\r
+                   (or (re-search-forward\r
+                        "\\=\\w+[ \t]*#\\([^\n\\\\#]\\|\\\\[\\\\#]\\)*#"\r
+                        lim 'move)\r
+                       (setq stop-in t)))\r
+                  (t                   ; It was fair comment\r
+                   (setq stop-in t)    ; Finish\r
+                   (goto-char (1- cpoint)))))\r
+             (setq stop-in t)          ; Finish\r
+             (forward-char -1))\r
+         (setq stop-in t)))            ; Finish \r
+      (nth 4 state))))\r
+\r
+(defsubst cperl-1- (p)\r
+  (max (point-min) (1- p)))\r
+\r
+(defsubst cperl-1+ (p)\r
+  (min (point-max) (1+ p)))\r
+\r
+(defsubst cperl-modify-syntax-type (at how)\r
+  (if (< at (point-max))\r
+      (progn\r
+       (put-text-property at (1+ at) 'syntax-table how)\r
+       (put-text-property at (1+ at) 'rear-nonsticky t))))\r
+\r
+(defun cperl-protect-defun-start (s e)\r
+  ;; C code looks for "^\\s(" to skip comment backward in "hard" situations\r
+  (save-excursion\r
+    (goto-char s)\r
+    (while (re-search-forward "^\\s(" e 'to-end)\r
+      (put-text-property (1- (point)) (point) 'syntax-table cperl-st-punct))))\r
+\r
+(defun cperl-commentify (bb e string &optional noface)\r
+  (if cperl-use-syntax-table-text-property\r
+      (if (eq noface 'n)               ; Only immediate\r
+         nil\r
+       ;; We suppose that e is _after_ the end of construction, as after eol.\r
+       (setq string (if string cperl-st-sfence cperl-st-cfence))\r
+       (if (> bb (- e 2))\r
+           ;; one-char string/comment?!\r
+           (cperl-modify-syntax-type bb cperl-st-punct)\r
+         (cperl-modify-syntax-type bb string)\r
+         (cperl-modify-syntax-type (1- e) string))\r
+       (if (and (eq string cperl-st-sfence) (> (- e 2) bb))\r
+           (put-text-property (1+ bb) (1- e)\r
+                              'syntax-table cperl-string-syntax-table))\r
+       (cperl-protect-defun-start bb e))\r
+    ;; Fontify\r
+    (or noface\r
+       (not cperl-pod-here-fontify)\r
+       (put-text-property bb e 'face (if string 'font-lock-string-face\r
+                                       'font-lock-comment-face)))))\r
+\r
+(defvar cperl-starters '(( ?\( . ?\) )\r
+                        ( ?\[ . ?\] )\r
+                        ( ?\{ . ?\} )\r
+                        ( ?\< . ?\> )))\r
+\r
+(defun cperl-forward-re (lim end is-2arg set-st st-l err-l argument\r
+                            &optional ostart oend)\r
+  ;; Works *before* syntax recognition is done\r
+  ;; May modify syntax-type text property if the situation is too hard\r
+  (let (b starter ender st i i2 go-forward reset-st)\r
+    (skip-chars-forward " \t")\r
+    ;; ender means matching-char matcher.\r
+    (setq b (point)\r
+         starter (if (eobp) 0 (char-after b))\r
+         ender (cdr (assoc starter cperl-starters)))\r
+    ;; What if starter == ?\\  ????\r
+    (if set-st\r
+       (if (car st-l)\r
+           (setq st (car st-l))\r
+         (setcar st-l (make-syntax-table))\r
+         (setq i 0 st (car st-l))\r
+         (while (< i 256)\r
+           (modify-syntax-entry i "." st)\r
+           (setq i (1+ i)))\r
+         (modify-syntax-entry ?\\ "\\" st)))\r
+    (setq set-st t)\r
+    ;; Whether we have an intermediate point\r
+    (setq i nil)\r
+    ;; Prepare the syntax table:\r
+    (and set-st\r
+        (if (not ender)                ; m/blah/, s/x//, s/x/y/\r
+            (modify-syntax-entry starter "$" st)\r
+          (modify-syntax-entry starter (concat "(" (list ender)) st)\r
+          (modify-syntax-entry ender  (concat ")" (list starter)) st)))\r
+    (condition-case bb\r
+       (progn\r
+         ;; We use `$' syntax class to find matching stuff, but $$\r
+         ;; is recognized the same as $, so we need to check this manually.\r
+         (if (and (eq starter (char-after (cperl-1+ b)))\r
+                  (not ender))\r
+             ;; $ has TeXish matching rules, so $$ equiv $...\r
+             (forward-char 2)\r
+           (setq reset-st (syntax-table))\r
+           (set-syntax-table st)\r
+           (forward-sexp 1)\r
+           (if (<= (point) (1+ b))\r
+               (error "Unfinished regular expression"))\r
+           (set-syntax-table reset-st)\r
+           (setq reset-st nil)\r
+           ;; Now the problem is with m;blah;;\r
+           (and (not ender)\r
+                (eq (preceding-char)\r
+                    (char-after (- (point) 2)))\r
+                (save-excursion\r
+                  (forward-char -2)\r
+                  (= 0 (% (skip-chars-backward "\\\\") 2)))\r
+                (forward-char -1)))\r
+         ;; Now we are after the first part.\r
+         (and is-2arg                  ; Have trailing part\r
+              (not ender)\r
+              (eq (following-char) starter) ; Empty trailing part\r
+              (progn\r
+                (or (eq (char-syntax (following-char)) ?.)\r
+                    ;; Make trailing letter into punctuation\r
+                    (cperl-modify-syntax-type (point) cperl-st-punct))\r
+                (setq is-2arg nil go-forward t))) ; Ignore the tail\r
+         (if is-2arg                   ; Not number => have second part\r
+             (progn\r
+               (setq i (point) i2 i)\r
+               (if ender\r
+                   (if (memq (following-char) '(?\  ?\t ?\n ?\f))\r
+                       (progn\r
+                         (if (looking-at "[ \t\n\f]+\\(#[^\n]*\n[ \t\n\f]*\\)+")\r
+                             (goto-char (match-end 0))\r
+                           (skip-chars-forward " \t\n\f"))\r
+                         (setq i2 (point))))\r
+                 (forward-char -1))\r
+               (modify-syntax-entry starter (if (eq starter ?\\) "\\" ".") st)\r
+               (if ender (modify-syntax-entry ender "." st))\r
+               (setq set-st nil)\r
+               (setq ender (cperl-forward-re lim end nil t st-l err-l\r
+                                             argument starter ender)\r
+                     ender (nth 2 ender)))))\r
+      (error (goto-char lim)\r
+            (setq set-st nil)\r
+            (if reset-st\r
+                (set-syntax-table reset-st))\r
+            (or end\r
+                (message\r
+                 "End of `%s%s%c ... %c' string/RE not found: %s"\r
+                 argument\r
+                 (if ostart (format "%c ... %c" ostart (or oend ostart)) "")\r
+                 starter (or ender starter) bb)\r
+                (or (car err-l) (setcar err-l b)))))\r
+    (if set-st\r
+       (progn\r
+         (modify-syntax-entry starter (if (eq starter ?\\) "\\" ".") st)\r
+         (if ender (modify-syntax-entry ender "." st))))\r
+    ;; i: have 2 args, after end of the first arg\r
+    ;; i2: start of the second arg, if any (before delim iff `ender').\r
+    ;; ender: the last arg bounded by parens-like chars, the second one of them\r
+    ;; starter: the starting delimiter of the first arg\r
+    ;; go-forward: has 2 args, and the second part is empty\r
+    (list i i2 ender starter go-forward)))\r
+\r
+(defvar font-lock-string-face)\r
+;;(defvar font-lock-reference-face)\r
+(defvar font-lock-constant-face)\r
+(defsubst cperl-postpone-fontification (b e type val &optional now)\r
+  ;; Do after syntactic fontification?\r
+  (if cperl-syntaxify-by-font-lock\r
+      (or now (put-text-property b e 'cperl-postpone (cons type val)))\r
+    (put-text-property b e type val)))\r
+\r
+;;; Here is how the global structures (those which cannot be\r
+;;; recognized locally) are marked:\r
+;;     a) PODs:\r
+;;             Start-to-end is marked `in-pod' ==> t\r
+;;             Each non-literal part is marked `syntax-type' ==> `pod'\r
+;;             Each literal part is marked `syntax-type' ==> `in-pod'\r
+;;     b) HEREs:\r
+;;             Start-to-end is marked `here-doc-group' ==> t\r
+;;             The body is marked `syntax-type' ==> `here-doc'\r
+;;             The delimiter is marked `syntax-type' ==> `here-doc-delim'\r
+;;     c) FORMATs:\r
+;;             First line (to =) marked `first-format-line' ==> t\r
+;;             After-this--to-end is marked `syntax-type' ==> `format'\r
+;;     d) 'Q'uoted string:\r
+;;             part between markers inclusive is marked `syntax-type' ==> `string'\r
+;;             part between `q' and the first marker is marked `syntax-type' ==> `prestring'\r
+\r
+(defun cperl-unwind-to-safe (before &optional end)\r
+  ;; if BEFORE, go to the previous start-of-line on each step of unwinding\r
+  (let ((pos (point)) opos)\r
+    (setq opos pos)\r
+    (while (and pos (get-text-property pos 'syntax-type))\r
+      (setq pos (previous-single-property-change pos 'syntax-type))\r
+      (if pos\r
+         (if before\r
+             (progn\r
+               (goto-char (cperl-1- pos))\r
+               (beginning-of-line)\r
+               (setq pos (point)))\r
+           (goto-char (setq pos (cperl-1- pos))))\r
+       ;; Up to the start\r
+       (goto-char (point-min))))\r
+    ;; Skip empty lines\r
+    (and (looking-at "\n*=")\r
+        (/= 0 (skip-chars-backward "\n"))\r
+        (forward-char))\r
+    (setq pos (point))\r
+    (if end\r
+       ;; Do the same for end, going small steps\r
+       (progn\r
+         (while (and end (get-text-property end 'syntax-type))\r
+           (setq pos end\r
+                 end (next-single-property-change end 'syntax-type)))\r
+         (or end pos)))))\r
+\r
+(defvar cperl-nonoverridable-face)\r
+(defvar font-lock-function-name-face)\r
+(defvar font-lock-comment-face)\r
+\r
+(defun cperl-find-pods-heres (&optional min max non-inter end ignore-max)\r
+  "Scans the buffer for hard-to-parse Perl constructions.\r
+If `cperl-pod-here-fontify' is not-nil after evaluation, will fontify\r
+the sections using `cperl-pod-head-face', `cperl-pod-face',\r
+`cperl-here-face'."\r
+  (interactive)\r
+  (or min (setq min (point-min)\r
+               cperl-syntax-state nil\r
+               cperl-syntax-done-to min))\r
+  (or max (setq max (point-max)))\r
+  (let* ((cperl-pod-here-fontify (eval cperl-pod-here-fontify)) go tmpend\r
+        face head-face here-face b e bb tag qtag b1 e1 argument i c tail tb\r
+        is-REx is-x-REx REx-comment-start REx-comment-end was-comment i2\r
+        (case-fold-search nil) (inhibit-read-only t) (buffer-undo-list t)\r
+        (modified (buffer-modified-p))\r
+        (after-change-functions nil)\r
+        (use-syntax-state (and cperl-syntax-state\r
+                               (>= min (car cperl-syntax-state))))\r
+        (state-point (if use-syntax-state\r
+                         (car cperl-syntax-state)\r
+                       (point-min)))\r
+        (state (if use-syntax-state\r
+                   (cdr cperl-syntax-state)))\r
+        ;; (st-l '(nil)) (err-l '(nil)) ; Would overwrite - propagates from a function call to a function call!\r
+        (st-l (list nil)) (err-l (list nil))\r
+        ;; Somehow font-lock may be not loaded yet...\r
+        (font-lock-string-face (if (boundp 'font-lock-string-face)\r
+                                   font-lock-string-face\r
+                                 'font-lock-string-face))\r
+        (font-lock-constant-face (if (boundp 'font-lock-constant-face)\r
+                                     font-lock-constant-face\r
+                                   'font-lock-constant-face))\r
+        (font-lock-function-name-face\r
+         (if (boundp 'font-lock-function-name-face)\r
+             font-lock-function-name-face\r
+           'font-lock-function-name-face))\r
+        (font-lock-comment-face\r
+         (if (boundp 'font-lock-comment-face)\r
+             font-lock-comment-face\r
+           'font-lock-comment-face))\r
+        (cperl-nonoverridable-face\r
+         (if (boundp 'cperl-nonoverridable-face)\r
+             cperl-nonoverridable-face\r
+           'cperl-nonoverridable-face))\r
+        (stop-point (if ignore-max\r
+                        (point-max)\r
+                      max))\r
+        (search\r
+         (concat\r
+          "\\(\\`\n?\\|^\n\\)="\r
+          "\\|"\r
+          ;; One extra () before this:\r
+          "<<"\r
+          "\\("                        ; 1 + 1\r
+          ;; First variant "BLAH" or just ``.\r
+          "[ \t]*"                     ; Yes, whitespace is allowed!\r
+          "\\([\"'`]\\)"               ; 2 + 1 = 3\r
+          "\\([^\"'`\n]*\\)"           ; 3 + 1\r
+          "\\3"\r
+          "\\|"\r
+          ;; Second variant: Identifier or \ID (same as 'ID') or empty\r
+          "\\\\?\\(\\([a-zA-Z_][a-zA-Z_0-9]*\\)?\\)" ; 4 + 1, 5 + 1\r
+          ;; Do not have <<= or << 30 or <<30 or << $blah.\r
+          ;; "\\([^= \t0-9$@%&]\\|[ \t]+[^ \t\n0-9$@%&]\\)" ; 6 + 1\r
+          "\\(\\)"             ; To preserve count of pars :-( 6 + 1\r
+          "\\)"\r
+          "\\|"\r
+          ;; 1+6 extra () before this:\r
+          "^[ \t]*\\(format\\)[ \t]*\\([a-zA-Z0-9_]+\\)?[ \t]*=[ \t]*$"\r
+          (if cperl-use-syntax-table-text-property\r
+              (concat\r
+               "\\|"\r
+               ;; 1+6+2=9 extra () before this:\r
+               "\\<\\(q[wxqr]?\\|[msy]\\|tr\\)\\>"\r
+               "\\|"\r
+               ;; 1+6+2+1=10 extra () before this:\r
+               "\\([?/<]\\)"   ; /blah/ or ?blah? or <file*glob>\r
+               "\\|"\r
+               ;; 1+6+2+1+1=11 extra () before this:\r
+               "\\<sub\\>[ \t]*\\([a-zA-Z_:'0-9]+[ \t]*\\)?\\(([^()]*)\\)"\r
+               "\\|"\r
+               ;; 1+6+2+1+1+2=13 extra () before this:\r
+               "\\$\\(['{]\\)"\r
+               "\\|"\r
+               ;; 1+6+2+1+1+2+1=14 extra () before this:\r
+               "\\(\\<sub[ \t\n\f]+\\|[&*$@%]\\)[a-zA-Z0-9_]*'"\r
+               ;; 1+6+2+1+1+2+1+1=15 extra () before this:\r
+               "\\|"\r
+               "__\\(END\\|DATA\\)__"\r
+               ;; 1+6+2+1+1+2+1+1+1=16 extra () before this:\r
+               "\\|"\r
+               "\\\\\\(['`\"($]\\)")\r
+            ""))))\r
+    (unwind-protect\r
+       (progn\r
+         (save-excursion\r
+           (or non-inter\r
+               (message "Scanning for \"hard\" Perl constructions..."))\r
+           (and cperl-pod-here-fontify\r
+                ;; We had evals here, do not know why...\r
+                (setq face cperl-pod-face\r
+                      head-face cperl-pod-head-face\r
+                      here-face cperl-here-face))\r
+           (remove-text-properties min max\r
+                                   '(syntax-type t in-pod t syntax-table t\r
+                                                 cperl-postpone t\r
+                                                 syntax-subtype t\r
+                                                 rear-nonsticky t\r
+                                                 here-doc-group t\r
+                                                 first-format-line t\r
+                                                 indentable t))\r
+           ;; Need to remove face as well...\r
+           (goto-char min)\r
+           (and (eq system-type 'emx)\r
+                (looking-at "extproc[ \t]") ; Analogue of #!\r
+                (cperl-commentify min\r
+                                  (save-excursion (end-of-line) (point))\r
+                                  nil))\r
+           (while (and\r
+                   (< (point) max)\r
+                   (re-search-forward search max t))\r
+             (setq tmpend nil)         ; Valid for most cases\r
+             (cond\r
+              ((match-beginning 1)     ; POD section\r
+               ;;  "\\(\\`\n?\\|^\n\\)="\r
+               (if (looking-at "cut\\>")\r
+                   (if ignore-max\r
+                       nil             ; Doing a chunk only\r
+                     (message "=cut is not preceded by a POD section")\r
+                     (or (car err-l) (setcar err-l (point))))\r
+                 (beginning-of-line)\r
+\r
+                 (setq b (point)\r
+                       bb b\r
+                       tb (match-beginning 0)\r
+                       b1 nil)         ; error condition\r
+                 ;; We do not search to max, since we may be called from\r
+                 ;; some hook of fontification, and max is random\r
+                 (or (re-search-forward "^\n=cut\\>" stop-point 'toend)\r
+                     (progn\r
+                       (goto-char b)\r
+                       (if (re-search-forward "\n=cut\\>" stop-point 'toend)\r
+                           (progn\r
+                             (message "=cut is not preceded by an empty line")\r
+                             (setq b1 t)\r
+                             (or (car err-l) (setcar err-l b))))))\r
+                 (beginning-of-line 2) ; An empty line after =cut is not POD!\r
+                 (setq e (point))\r
+                 (and (> e max)\r
+                      (progn\r
+                        (remove-text-properties\r
+                         max e '(syntax-type t in-pod t syntax-table t\r
+                                             cperl-postpone t\r
+                                             syntax-subtype t\r
+                                             here-doc-group t\r
+                                             rear-nonsticky t\r
+                                             first-format-line t\r
+                                             indentable t))\r
+                        (setq tmpend tb)))\r
+                 (put-text-property b e 'in-pod t)\r
+                 (put-text-property b e 'syntax-type 'in-pod)\r
+                 (goto-char b)\r
+                 (while (re-search-forward "\n\n[ \t]" e t)\r
+                   ;; We start 'pod 1 char earlier to include the preceding line\r
+                   (beginning-of-line)\r
+                   (put-text-property (cperl-1- b) (point) 'syntax-type 'pod)\r
+                   (cperl-put-do-not-fontify b (point) t)\r
+                   ;; mark the non-literal parts as PODs\r
+                   (if cperl-pod-here-fontify\r
+                       (cperl-postpone-fontification b (point) 'face face t))\r
+                   (re-search-forward "\n\n[^ \t\f\n]" e 'toend)\r
+                   (beginning-of-line)\r
+                   (setq b (point)))\r
+                 (put-text-property (cperl-1- (point)) e 'syntax-type 'pod)\r
+                 (cperl-put-do-not-fontify (point) e t)\r
+                 (if cperl-pod-here-fontify\r
+                     (progn\r
+                       ;; mark the non-literal parts as PODs\r
+                       (cperl-postpone-fontification (point) e 'face face t)\r
+                       (goto-char bb)\r
+                       (if (looking-at\r
+                            "=[a-zA-Z0-9_]+\\>[ \t]*\\(\\(\n?[^\n]\\)+\\)$")\r
+                           ;; mark the headers\r
+                           (cperl-postpone-fontification\r
+                            (match-beginning 1) (match-end 1)\r
+                            'face head-face))\r
+                       (while (re-search-forward\r
+                               ;; One paragraph\r
+                               "^\n=[a-zA-Z0-9_]+\\>[ \t]*\\(\\(\n?[^\n]\\)+\\)$"\r
+                               e 'toend)\r
+                         ;; mark the headers\r
+                         (cperl-postpone-fontification\r
+                          (match-beginning 1) (match-end 1)\r
+                          'face head-face))))\r
+                 (cperl-commentify bb e nil)\r
+                 (goto-char e)\r
+                 (or (eq e (point-max))\r
+                     (forward-char -1)))) ; Prepare for immediate POD start.\r
+              ;; Here document\r
+              ;; We do only one here-per-line\r
+               ;; ;; One extra () before this:\r
+              ;;"<<"\r
+              ;;  "\\("                        ; 1 + 1\r
+              ;;  ;; First variant "BLAH" or just ``.\r
+              ;;     "[ \t]*"                  ; Yes, whitespace is allowed!\r
+              ;;     "\\([\"'`]\\)"    ; 2 + 1\r
+              ;;     "\\([^\"'`\n]*\\)"        ; 3 + 1\r
+              ;;     "\\3"\r
+              ;;  "\\|"\r
+              ;;  ;; Second variant: Identifier or \ID or empty\r
+              ;;    "\\\\?\\(\\([a-zA-Z_][a-zA-Z_0-9]*\\)?\\)" ; 4 + 1, 5 + 1\r
+              ;;    ;; Do not have <<= or << 30 or <<30 or << $blah.\r
+              ;;    ;; "\\([^= \t0-9$@%&]\\|[ \t]+[^ \t\n0-9$@%&]\\)" ; 6 + 1\r
+              ;;    "\\(\\)"           ; To preserve count of pars :-( 6 + 1\r
+              ;;  "\\)"\r
+              ((match-beginning 2)     ; 1 + 1\r
+               ;; Abort in comment:\r
+               (setq b (point))\r
+               (setq state (parse-partial-sexp state-point b nil nil state)\r
+                     state-point b\r
+                     tb (match-beginning 0)\r
+                     i (or (nth 3 state) (nth 4 state)))\r
+               (if i\r
+                   (setq c t)\r
+                 (setq c (and\r
+                          (match-beginning 5)\r
+                          (not (match-beginning 6)) ; Empty\r
+                          (looking-at\r
+                           "[ \t]*[=0-9$@%&(]"))))\r
+               (if c                   ; Not here-doc\r
+                   nil                 ; Skip it.\r
+                 (if (match-beginning 5) ;4 + 1\r
+                     (setq b1 (match-beginning 5) ; 4 + 1\r
+                           e1 (match-end 5)) ; 4 + 1\r
+                   (setq b1 (match-beginning 4) ; 3 + 1\r
+                         e1 (match-end 4))) ; 3 + 1\r
+                 (setq tag (buffer-substring b1 e1)\r
+                       qtag (regexp-quote tag))\r
+                 (cond (cperl-pod-here-fontify\r
+                        ;; Highlight the starting delimiter\r
+                        (cperl-postpone-fontification b1 e1 'face font-lock-constant-face)\r
+                        (cperl-put-do-not-fontify b1 e1 t)))\r
+                 (forward-line)\r
+                 (setq b (point))\r
+                 ;; We do not search to max, since we may be called from\r
+                 ;; some hook of fontification, and max is random\r
+                 (or (and (re-search-forward (concat "^" qtag "$")\r
+                                             stop-point 'toend)\r
+                          (eq (following-char) ?\n))\r
+                   (progn              ; Pretend we matched at the end\r
+                     (goto-char (point-max))\r
+                     (re-search-forward "\\'")\r
+                     (message "End of here-document `%s' not found." tag)\r
+                     (or (car err-l) (setcar err-l b))))\r
+                 (if cperl-pod-here-fontify\r
+                     (progn\r
+                       ;; Highlight the ending delimiter\r
+                       (cperl-postpone-fontification (match-beginning 0) (match-end 0)\r
+                                                     'face font-lock-constant-face)\r
+                       (cperl-put-do-not-fontify b (match-end 0) t)\r
+                       ;; Highlight the HERE-DOC\r
+                       (cperl-postpone-fontification b (match-beginning 0)\r
+                                                     'face here-face)))\r
+                 (setq e1 (cperl-1+ (match-end 0)))\r
+                 (put-text-property b (match-beginning 0)\r
+                                    'syntax-type 'here-doc)\r
+                 (put-text-property (match-beginning 0) e1\r
+                                    'syntax-type 'here-doc-delim)\r
+                 (put-text-property b e1\r
+                                    'here-doc-group t)\r
+                 (cperl-commentify b e1 nil)\r
+                 (cperl-put-do-not-fontify b (match-end 0) t)\r
+                 (if (> e1 max)\r
+                     (setq tmpend tb))))\r
+              ;; format\r
+              ((match-beginning 8)\r
+               ;; 1+6=7 extra () before this:\r
+               ;;"^[ \t]*\\(format\\)[ \t]*\\([a-zA-Z0-9_]+\\)?[ \t]*=[ \t]*$"\r
+               (setq b (point)\r
+                     name (if (match-beginning 8) ; 7 + 1\r
+                              (buffer-substring (match-beginning 8) ; 7 + 1\r
+                                                (match-end 8)) ; 7 + 1\r
+                            "")\r
+                     tb (match-beginning 0))\r
+               (setq argument nil)\r
+               (put-text-property (save-excursion\r
+                                    (beginning-of-line)\r
+                                    (point))\r
+                                  b 'first-format-line 't)\r
+               (if cperl-pod-here-fontify\r
+                   (while (and (eq (forward-line) 0)\r
+                               (not (looking-at "^[.;]$")))\r
+                     (cond\r
+                      ((looking-at "^#")) ; Skip comments\r
+                      ((and argument   ; Skip argument multi-lines\r
+                            (looking-at "^[ \t]*{"))\r
+                       (forward-sexp 1)\r
+                       (setq argument nil))\r
+                      (argument        ; Skip argument lines\r
+                       (setq argument nil))\r
+                      (t               ; Format line\r
+                       (setq b1 (point))\r
+                       (setq argument (looking-at "^[^\n]*[@^]"))\r
+                       (end-of-line)\r
+                       ;; Highlight the format line\r
+                       (cperl-postpone-fontification b1 (point)\r
+                                                     'face font-lock-string-face)\r
+                       (cperl-commentify b1 (point) nil)\r
+                       (cperl-put-do-not-fontify b1 (point) t))))\r
+                 ;; We do not search to max, since we may be called from\r
+                 ;; some hook of fontification, and max is random\r
+                 (re-search-forward "^[.;]$" stop-point 'toend))\r
+               (beginning-of-line)\r
+               (if (looking-at "^\\.$") ; ";" is not supported yet\r
+                   (progn\r
+                     ;; Highlight the ending delimiter\r
+                     (cperl-postpone-fontification (point) (+ (point) 2)\r
+                                                   'face font-lock-string-face)\r
+                     (cperl-commentify (point) (+ (point) 2) nil)\r
+                     (cperl-put-do-not-fontify (point) (+ (point) 2) t))\r
+                 (message "End of format `%s' not found." name)\r
+                 (or (car err-l) (setcar err-l b)))\r
+               (forward-line)\r
+               (if (> (point) max)\r
+                   (setq tmpend tb))\r
+               (put-text-property b (point) 'syntax-type 'format))\r
+              ;; Regexp:\r
+              ((or (match-beginning 10) (match-beginning 11))\r
+               ;; 1+6+2=9 extra () before this:\r
+               ;; "\\<\\(q[wxqr]?\\|[msy]\\|tr\\)\\>"\r
+               ;; "\\|"\r
+               ;; "\\([?/<]\\)"        ; /blah/ or ?blah? or <file*glob>\r
+               (setq b1 (if (match-beginning 10) 10 11)\r
+                     argument (buffer-substring\r
+                               (match-beginning b1) (match-end b1))\r
+                     b (point)\r
+                     i b\r
+                     c (char-after (match-beginning b1))\r
+                     bb (char-after (1- (match-beginning b1))) ; tmp holder\r
+                     ;; bb == "Not a stringy"\r
+                     bb (if (eq b1 10) ; user variables/whatever\r
+                            (and (memq bb (append "$@%*#_:-&>" nil)) ; $#y)\r
+                                 (cond ((eq bb ?-) (eq c ?s)) ; -s file test\r
+                                       ((eq bb ?\:) ; $opt::s\r
+                                        (eq (char-after\r
+                                             (- (match-beginning b1) 2))\r
+                                            ?\:))\r
+                                       ((eq bb ?\>) ; $foo->s\r
+                                        (eq (char-after\r
+                                             (- (match-beginning b1) 2))\r
+                                            ?\-))\r
+                                       ((eq bb ?\&)\r
+                                        (not (eq (char-after   ; &&m/blah/\r
+                                                  (- (match-beginning b1) 2))\r
+                                                 ?\&)))\r
+                                       (t t)))\r
+                          ;; <file> or <$file>\r
+                          (and (eq c ?\<)\r
+                               ;; Do not stringify <FH>, <$fh> :\r
+                               (save-match-data\r
+                                 (looking-at\r
+                                  "\\$?\\([_a-zA-Z:][_a-zA-Z0-9:]*\\)?>"))))\r
+                     tb (match-beginning 0))\r
+               (goto-char (match-beginning b1))\r
+               (cperl-backward-to-noncomment (point-min))\r
+               (or bb\r
+                   (if (eq b1 11)      ; bare /blah/ or ?blah? or <foo>\r
+                       (setq argument ""\r
+                             b1 nil\r
+                             bb        ; Not a regexp?\r
+                             (progn\r
+                               (not\r
+                                ;; What is below: regexp-p?\r
+                                (and\r
+                                 (or (memq (preceding-char)\r
+                                           (append (if (memq c '(?\? ?\<))\r
+                                                       ;; $a++ ? 1 : 2\r
+                                                       "~{(=|&*!,;:"\r
+                                                     "~{(=|&+-*!,;:") nil))\r
+                                     (and (eq (preceding-char) ?\})\r
+                                          (cperl-after-block-p (point-min)))\r
+                                     (and (eq (char-syntax (preceding-char)) ?w)\r
+                                          (progn\r
+                                            (forward-sexp -1)\r
+;;; After these keywords `/' starts a RE.  One should add all the\r
+;;; functions/builtins which expect an argument, but ...\r
+                                            (if (eq (preceding-char) ?-)\r
+                                                ;; -d ?foo? is a RE\r
+                                                (looking-at "[a-zA-Z]\\>")\r
+                                              (and\r
+                                               (not (memq (preceding-char)\r
+                                                          '(?$ ?@ ?& ?%)))\r
+                                               (looking-at\r
+                                                "\\(while\\|if\\|unless\\|until\\|and\\|or\\|not\\|xor\\|split\\|grep\\|map\\|print\\)\\>")))))\r
+                                     (and (eq (preceding-char) ?.)\r
+                                          (eq (char-after (- (point) 2)) ?.))\r
+                                     (bobp))\r
+                                 ;;  m|blah| ? foo : bar;\r
+                                 (not\r
+                                  (and (eq c ?\?)\r
+                                       cperl-use-syntax-table-text-property\r
+                                       (not (bobp))\r
+                                       (progn\r
+                                         (forward-char -1)\r
+                                         (looking-at "\\s|")))))))\r
+                             b (1- b))\r
+                     ;; s y tr m\r
+                     ;; Check for $a -> y\r
+                     (setq b1 (preceding-char)\r
+                           go (point))\r
+                     (if (and (eq b1 ?>)\r
+                              (eq (char-after (- go 2)) ?-))\r
+                         ;; Not a regexp\r
+                         (setq bb t))))\r
+               (or bb (setq state (parse-partial-sexp\r
+                                   state-point b nil nil state)\r
+                            state-point b))\r
+               (setq bb (or bb (nth 3 state) (nth 4 state)))\r
+               (goto-char b)\r
+               (or bb\r
+                   (progn\r
+                     (if (looking-at "[ \t\n\f]+\\(#[^\n]*\n[ \t\n\f]*\\)+")\r
+                         (goto-char (match-end 0))\r
+                       (skip-chars-forward " \t\n\f"))\r
+                     (cond ((and (eq (following-char) ?\})\r
+                                 (eq b1 ?\{))\r
+                            ;; Check for $a[23]->{ s }, @{s} and *{s::foo}\r
+                            (goto-char (1- go))\r
+                            (skip-chars-backward " \t\n\f")\r
+                            (if (memq (preceding-char) (append "$@%&*" nil))\r
+                                (setq bb t) ; @{y}\r
+                              (condition-case nil\r
+                                  (forward-sexp -1)\r
+                                (error nil)))\r
+                            (if (or bb\r
+                                    (looking-at ; $foo -> {s}\r
+                                     "[$@]\\$*\\([a-zA-Z0-9_:]+\\|[^{]\\)\\([ \t\n]*->\\)?[ \t\n]*{")\r
+                                    (and ; $foo[12] -> {s}\r
+                                     (memq (following-char) '(?\{ ?\[))\r
+                                     (progn\r
+                                       (forward-sexp 1)\r
+                                       (looking-at "\\([ \t\n]*->\\)?[ \t\n]*{"))))\r
+                                (setq bb t)\r
+                              (goto-char b)))\r
+                           ((and (eq (following-char) ?=)\r
+                                 (eq (char-after (1+ (point))) ?\>))\r
+                            ;; Check for { foo => 1, s => 2 }\r
+                            ;; Apparently s=> is never a substitution...\r
+                            (setq bb t))\r
+                           ((and (eq (following-char) ?:)\r
+                                 (eq b1 ?\{) ; Check for $ { s::bar }\r
+                                 (looking-at "::[a-zA-Z0-9_:]*[ \t\n\f]*}")\r
+                                 (progn \r
+                                   (goto-char (1- go))\r
+                                   (skip-chars-backward " \t\n\f")\r
+                                   (memq (preceding-char)\r
+                                         (append "$@%&*" nil))))\r
+                            (setq bb t)))))\r
+               (if bb\r
+                   (goto-char i)\r
+                 ;; Skip whitespace and comments...\r
+                 (if (looking-at "[ \t\n\f]+\\(#[^\n]*\n[ \t\n\f]*\\)+")\r
+                     (goto-char (match-end 0))\r
+                   (skip-chars-forward " \t\n\f"))\r
+                 (if (> (point) b)\r
+                     (put-text-property b (point) 'syntax-type 'prestring))\r
+                 ;; qtag means two-arg matcher, may be reset to\r
+                 ;;   2 or 3 later if some special quoting is needed.\r
+                 ;; e1 means matching-char matcher.\r
+                 (setq b (point)\r
+                       ;; has 2 args\r
+                       i2 (string-match "^\\([sy]\\|tr\\)$" argument)\r
+                       ;; We do not search to max, since we may be called from\r
+                       ;; some hook of fontification, and max is random\r
+                       i (cperl-forward-re stop-point end\r
+                                           i2\r
+                                           t st-l err-l argument)\r
+                       ;; Note that if `go', then it is considered as 1-arg\r
+                       b1 (nth 1 i)    ; start of the second part\r
+                       tag (nth 2 i)   ; ender-char, true if second part\r
+                                       ; is with matching chars []\r
+                       go (nth 4 i)    ; There is a 1-char part after the end\r
+                       i (car i)       ; intermediate point\r
+                       e1 (point)      ; end\r
+                       ;; Before end of the second part if non-matching: ///\r
+                       tail (if (and i (not tag))\r
+                                (1- e1))\r
+                       e (if i i e1)   ; end of the first part\r
+                       qtag nil        ; need to preserve backslashitis\r
+                       is-x-REx nil)   ; REx has //x modifier\r
+                 ;; Commenting \\ is dangerous, what about ( ?\r
+                 (and i tail\r
+                      (eq (char-after i) ?\\)\r
+                      (setq qtag t))\r
+                 (if (looking-at "\\sw*x") ; qr//x\r
+                     (setq is-x-REx t))\r
+                 (if (null i)\r
+                     ;; Considered as 1arg form\r
+                     (progn\r
+                       (cperl-commentify b (point) t)\r
+                       (put-text-property b (point) 'syntax-type 'string)\r
+                       (if (or is-x-REx\r
+                               ;; ignore other text properties:\r
+                               (string-match "^qw$" argument))\r
+                           (put-text-property b (point) 'indentable t))\r
+                       (and go\r
+                            (setq e1 (cperl-1+ e1))\r
+                            (or (eobp)\r
+                                (forward-char 1))))\r
+                   (cperl-commentify b i t)\r
+                   (if (looking-at "\\sw*e") ; s///e\r
+                       (progn\r
+                         (and\r
+                          ;; silent:\r
+                          (cperl-find-pods-heres b1 (1- (point)) t end)\r
+                          ;; Error\r
+                          (goto-char (1+ max)))\r
+                         (if (and tag (eq (preceding-char) ?\>))\r
+                             (progn\r
+                               (cperl-modify-syntax-type (1- (point)) cperl-st-ket)\r
+                               (cperl-modify-syntax-type i cperl-st-bra)))\r
+                         (put-text-property b i 'syntax-type 'string)\r
+                         (if is-x-REx\r
+                             (put-text-property b i 'indentable t)))\r
+                     (cperl-commentify b1 (point) t)\r
+                     (put-text-property b (point) 'syntax-type 'string)\r
+                     (if is-x-REx\r
+                         (put-text-property b i 'indentable t))\r
+                     (if qtag\r
+                         (cperl-modify-syntax-type (1+ i) cperl-st-punct))\r
+                     (setq tail nil)))\r
+                 ;; Now: tail: if the second part is non-matching without ///e\r
+                 (if (eq (char-syntax (following-char)) ?w)\r
+                     (progn\r
+                       (forward-word 1) ; skip modifiers s///s\r
+                       (if tail (cperl-commentify tail (point) t))\r
+                       (cperl-postpone-fontification\r
+                        e1 (point) 'face 'cperl-nonoverridable-face)))\r
+                 ;; Check whether it is m// which means "previous match"\r
+                 ;; and highlight differently\r
+                 (setq is-REx\r
+                       (and (string-match "^\\([sm]?\\|qr\\)$" argument)\r
+                            (or (not (= (length argument) 0))\r
+                                (not (eq c ?\<)))))\r
+                 (if (and is-REx\r
+                          (eq e (+ 2 b))\r
+                          ;; split // *is* using zero-pattern\r
+                          (save-excursion\r
+                            (condition-case nil\r
+                                (progn\r
+                                  (goto-char tb)\r
+                                  (forward-sexp -1)\r
+                                  (not (looking-at "split\\>")))\r
+                              (error t))))\r
+                     (cperl-postpone-fontification\r
+                      b e 'face font-lock-function-name-face)\r
+                   (if (or i2          ; Has 2 args\r
+                           (and cperl-fontify-m-as-s\r
+                                (or\r
+                                 (string-match "^\\(m\\|qr\\)$" argument)\r
+                                 (and (eq 0 (length argument))\r
+                                      (not (eq ?\< (char-after b)))))))\r
+                       (progn\r
+                         (cperl-postpone-fontification\r
+                          b (cperl-1+ b) 'face font-lock-constant-face)\r
+                         (cperl-postpone-fontification\r
+                          (1- e) e 'face font-lock-constant-face)))\r
+                   (if (and is-REx cperl-regexp-scan)\r
+                       ;; Process RExen better\r
+                       (save-excursion\r
+                         (goto-char (1+ b))\r
+                         (while\r
+                             (and (< (point) e)\r
+                                  (re-search-forward\r
+                                   (if is-x-REx\r
+                                       (if (eq (char-after b) ?\#)\r
+                                           "\\((\\?\\\\#\\)\\|\\(\\\\#\\)"\r
+                                         "\\((\\?#\\)\\|\\(#\\)")\r
+                                     (if (eq (char-after b) ?\#)\r
+                                         "\\((\\?\\\\#\\)"\r
+                                       "\\((\\?#\\)"))\r
+                                   (1- e) 'to-end))\r
+                           (goto-char (match-beginning 0))\r
+                           (setq REx-comment-start (point)\r
+                                 was-comment t)\r
+                           (if (save-excursion\r
+                                 (and\r
+                                  ;; XXX not working if outside delimiter is #\r
+                                  (eq (preceding-char) ?\\)\r
+                                  (= (% (skip-chars-backward "$\\\\") 2) -1)))\r
+                               ;; Not a comment, avoid loop:\r
+                               (progn (setq was-comment nil)\r
+                                      (forward-char 1))\r
+                             (if (match-beginning 2)\r
+                                 (progn\r
+                                   (beginning-of-line 2)\r
+                                   (if (> (point) e)\r
+                                       (goto-char (1- e))))\r
+                               ;; Works also if the outside delimiters are ().\r
+                               (or (search-forward ")" (1- e) 'toend)\r
+                                   (message\r
+                                    "Couldn't find end of (?#...)-comment in a REx, pos=%s"\r
+                                    REx-comment-start))))\r
+                           (if (>= (point) e)\r
+                               (goto-char (1- e)))\r
+                           (if was-comment\r
+                               (progn\r
+                                 (setq REx-comment-end (point))\r
+                                 (cperl-commentify\r
+                                  REx-comment-start REx-comment-end nil)\r
+                                 (cperl-postpone-fontification\r
+                                  REx-comment-start REx-comment-end\r
+                                  'face font-lock-comment-face))))))\r
+                   (if (and is-REx is-x-REx)\r
+                       (put-text-property (1+ b) (1- e)\r
+                                          'syntax-subtype 'x-REx)))\r
+                 (if i2\r
+                     (progn\r
+                       (cperl-postpone-fontification\r
+                        (1- e1) e1 'face font-lock-constant-face)\r
+                       (if (assoc (char-after b) cperl-starters)\r
+                           (cperl-postpone-fontification\r
+                            b1 (1+ b1) 'face font-lock-constant-face))))\r
+                 (if (> (point) max)\r
+                     (setq tmpend tb))))\r
+              ((match-beginning 13)    ; sub with prototypes\r
+               (setq b (match-beginning 0))\r
+               (if (memq (char-after (1- b))\r
+                         '(?\$ ?\@ ?\% ?\& ?\*))\r
+                   nil\r
+                 (setq state (parse-partial-sexp\r
+                              state-point b nil nil state)\r
+                       state-point b)\r
+                 (if (or (nth 3 state) (nth 4 state))\r
+                     nil\r
+                   ;; Mark as string\r
+                   (cperl-commentify (match-beginning 13) (match-end 13) t))\r
+                 (goto-char (match-end 0))))\r
+              ;; 1+6+2+1+1+2=13 extra () before this:\r
+              ;;    "\\$\\(['{]\\)"\r
+              ((and (match-beginning 14)\r
+                    (eq (preceding-char) ?\')) ; $'\r
+               (setq b (1- (point))\r
+                     state (parse-partial-sexp\r
+                            state-point (1- b) nil nil state)\r
+                     state-point (1- b))\r
+               (if (nth 3 state)       ; in string\r
+                   (cperl-modify-syntax-type (1- b) cperl-st-punct))\r
+               (goto-char (1+ b)))\r
+              ;; 1+6+2+1+1+2=13 extra () before this:\r
+              ;;    "\\$\\(['{]\\)"\r
+              ((match-beginning 14)    ; ${\r
+               (setq bb (match-beginning 0))\r
+               (cperl-modify-syntax-type bb cperl-st-punct))\r
+              ;; 1+6+2+1+1+2+1=14 extra () before this:\r
+              ;;    "\\(\\<sub[ \t\n\f]+\\|[&*$@%]\\)[a-zA-Z0-9_]*'")\r
+              ((match-beginning 15)    ; old $abc'efg syntax\r
+               (setq bb (match-end 0)\r
+                     b (match-beginning 0)\r
+                     state (parse-partial-sexp\r
+                            state-point b nil nil state)\r
+                     state-point b)\r
+               (if (nth 3 state)       ; in string\r
+                   nil\r
+                 (put-text-property (1- bb) bb 'syntax-table cperl-st-word))\r
+               (goto-char bb))\r
+              ;; 1+6+2+1+1+2+1+1=15 extra () before this:\r
+              ;; "__\\(END\\|DATA\\)__"\r
+              ((match-beginning 16)    ; __END__, __DATA__\r
+               (setq bb (match-end 0)\r
+                     b (match-beginning 0)\r
+                     state (parse-partial-sexp\r
+                            state-point b nil nil state)\r
+                     state-point b)\r
+               (if (or (nth 3 state) (nth 4 state))\r
+                   nil\r
+                 ;; (put-text-property b (1+ bb) 'syntax-type 'pod) ; Cheat\r
+                 (cperl-commentify b bb nil)\r
+                 (setq end t))\r
+               (goto-char bb))\r
+              ((match-beginning 17)    ; "\\\\\\(['`\"($]\\)"\r
+               ;; Trailing backslash ==> non-quoting outside string/comment\r
+               (setq bb (match-end 0)\r
+                     b (match-beginning 0))\r
+               (goto-char b)\r
+               (skip-chars-backward "\\\\")\r
+               ;;;(setq i2 (= (% (skip-chars-backward "\\\\") 2) -1))\r
+               (setq state (parse-partial-sexp\r
+                            state-point b nil nil state)\r
+                     state-point b)\r
+               (if (or (nth 3 state) (nth 4 state) )\r
+                   nil\r
+                 (cperl-modify-syntax-type b cperl-st-punct))\r
+               (goto-char bb))\r
+              (t (error "Error in regexp of the sniffer")))\r
+             (if (> (point) stop-point)\r
+                 (progn\r
+                   (if end\r
+                       (message "Garbage after __END__/__DATA__ ignored")\r
+                     (message "Unbalanced syntax found while scanning")\r
+                     (or (car err-l) (setcar err-l b)))\r
+                   (goto-char stop-point))))\r
+           (setq cperl-syntax-state (cons state-point state)\r
+                 cperl-syntax-done-to (or tmpend (max (point) max))))\r
+         (if (car err-l) (goto-char (car err-l))\r
+           (or non-inter\r
+               (message "Scanning for \"hard\" Perl constructions... done"))))\r
+      (and (buffer-modified-p)\r
+          (not modified)\r
+          (set-buffer-modified-p nil))\r
+      (set-syntax-table cperl-mode-syntax-table))\r
+    (car err-l)))\r
+\r
+(defun cperl-backward-to-noncomment (lim)\r
+  ;; Stops at lim or after non-whitespace that is not in comment\r
+  (let (stop p pr)\r
+    (while (and (not stop) (> (point) (or lim 1)))\r
+      (skip-chars-backward " \t\n\f" lim)\r
+      (setq p (point))\r
+      (beginning-of-line)\r
+      (if (memq (setq pr (get-text-property (point) 'syntax-type))\r
+               '(pod here-doc here-doc-delim))\r
+         (cperl-unwind-to-safe nil)\r
+      (or (looking-at "^[ \t]*\\(#\\|$\\)")\r
+         (progn (cperl-to-comment-or-eol) (bolp))\r
+         (progn\r
+           (skip-chars-backward " \t")\r
+           (if (< p (point)) (goto-char p))\r
+           (setq stop t)))))))\r
+\r
+(defun cperl-after-block-p (lim &optional pre-block)\r
+  "Return true if the preceeding } ends a block or a following { starts one.\r
+Would not look before LIM.  If PRE-BLOCK is nil checks preceeding }.\r
+otherwise following {."\r
+  ;; We suppose that the preceding char is }.\r
+  (save-excursion\r
+    (condition-case nil\r
+       (progn\r
+         (or pre-block (forward-sexp -1))\r
+         (cperl-backward-to-noncomment lim)\r
+         (or (eq (point) lim)\r
+             (eq (preceding-char) ?\) ) ; if () {}    sub f () {}\r
+             (if (eq (char-syntax (preceding-char)) ?w) ; else {}\r
+                 (save-excursion\r
+                   (forward-sexp -1)\r
+                   (or (looking-at "\\(else\\|continue\\|grep\\|map\\|BEGIN\\|END\\|CHECK\\|INIT\\)\\>")\r
+                       ;; sub f {}\r
+                       (progn\r
+                         (cperl-backward-to-noncomment lim)\r
+                         (and (eq (char-syntax (preceding-char)) ?w)\r
+                              (progn\r
+                                (forward-sexp -1)\r
+                                (looking-at "sub\\>"))))))\r
+               (cperl-after-expr-p lim))))\r
+      (error nil))))\r
+\r
+(defun cperl-after-expr-p (&optional lim chars test)\r
+  "Return true if the position is good for start of expression.\r
+TEST is the expression to evaluate at the found position.  If absent,\r
+CHARS is a string that contains good characters to have before us (however,\r
+`}' is treated \"smartly\" if it is not in the list)."\r
+  (let ((lim (or lim (point-min)))\r
+       stop p pr)\r
+    (cperl-update-syntaxification (point) (point))\r
+    (save-excursion\r
+      (while (and (not stop) (> (point) lim))\r
+       (skip-chars-backward " \t\n\f" lim)\r
+       (setq p (point))\r
+       (beginning-of-line)\r
+       ;;(memq (setq pr (get-text-property (point) 'syntax-type))\r
+       ;;      '(pod here-doc here-doc-delim))\r
+       (if (get-text-property (point) 'here-doc-group)\r
+           (progn\r
+             (goto-char\r
+              (previous-single-property-change (point) 'here-doc-group))\r
+             (beginning-of-line 0)))\r
+       (if (get-text-property (point) 'in-pod)\r
+           (progn\r
+             (goto-char\r
+              (previous-single-property-change (point) 'in-pod))\r
+             (beginning-of-line 0)))\r
+       (if (looking-at "^[ \t]*\\(#\\|$\\)") nil ; Only comment, skip\r
+         ;; Else: last iteration, or a label\r
+         (cperl-to-comment-or-eol)     ; Will not move past "." after a format\r
+         (skip-chars-backward " \t")\r
+         (if (< p (point)) (goto-char p))\r
+         (setq p (point))\r
+         (if (and (eq (preceding-char) ?:)\r
+                  (progn\r
+                    (forward-char -1)\r
+                    (skip-chars-backward " \t\n\f" lim)\r
+                    (eq (char-syntax (preceding-char)) ?w)))\r
+             (forward-sexp -1)         ; Possibly label.  Skip it\r
+           (goto-char p)\r
+           (setq stop t))))\r
+      (or (bobp)                       ; ???? Needed\r
+         (eq (point) lim)\r
+         (looking-at "[ \t]*__\\(END\\|DATA\\)__") ; After this anything goes\r
+         (progn\r
+           (if test (eval test)\r
+             (or (memq (preceding-char) (append (or chars "{;") nil))\r
+                 (and (eq (preceding-char) ?\})\r
+                      (cperl-after-block-p lim))\r
+                 (and (eq (following-char) ?.) ; in format: see comment above\r
+                      (eq (get-text-property (point) 'syntax-type)\r
+                          'format)))))))))\r
+\r
+(defun cperl-backward-to-start-of-continued-exp (lim)\r
+  (if (memq (preceding-char) (append ")]}\"'`" nil))\r
+      (forward-sexp -1))\r
+  (beginning-of-line)\r
+  (if (<= (point) lim)\r
+      (goto-char (1+ lim)))\r
+  (skip-chars-forward " \t"))\r
+\r
+(defun cperl-after-block-and-statement-beg (lim)\r
+  ;; We assume that we are after ?\}\r
+  (and\r
+   (cperl-after-block-p lim)\r
+   (save-excursion\r
+     (forward-sexp -1)\r
+     (cperl-backward-to-noncomment (point-min))\r
+     (or (bobp)\r
+        (eq (point) lim)\r
+        (not (= (char-syntax (preceding-char)) ?w))\r
+        (progn\r
+          (forward-sexp -1)\r
+          (not\r
+           (looking-at\r
+            "\\(map\\|grep\\|printf?\\|system\\|exec\\|tr\\|s\\)\\>")))))))\r
+\r
+\f\r
+(defvar innerloop-done nil)\r
+(defvar last-depth nil)\r
+\r
+(defun cperl-indent-exp ()\r
+  "Simple variant of indentation of continued-sexp.\r
+\r
+Will not indent comment if it starts at `comment-indent' or looks like\r
+continuation of the comment on the previous line.\r
+\r
+If `cperl-indent-region-fix-constructs', will improve spacing on\r
+conditional/loop constructs."\r
+  (interactive)\r
+  (save-excursion\r
+    (let ((tmp-end (progn (end-of-line) (point))) top done)\r
+      (save-excursion\r
+       (beginning-of-line)\r
+       (while (null done)\r
+         (setq top (point))\r
+         (while (= (nth 0 (parse-partial-sexp (point) tmp-end\r
+                                              -1)) -1)\r
+           (setq top (point)))         ; Get the outermost parenths in line\r
+         (goto-char top)\r
+         (while (< (point) tmp-end)\r
+           (parse-partial-sexp (point) tmp-end nil t) ; To start-sexp or eol\r
+           (or (eolp) (forward-sexp 1)))\r
+         (if (> (point) tmp-end)\r
+             (save-excursion\r
+               (end-of-line)\r
+               (setq tmp-end (point)))\r
+           (setq done t)))\r
+       (goto-char tmp-end)\r
+       (setq tmp-end (point-marker)))\r
+      (if cperl-indent-region-fix-constructs\r
+         (cperl-fix-line-spacing tmp-end))\r
+      (cperl-indent-region (point) tmp-end))))\r
+\r
+(defun cperl-fix-line-spacing (&optional end parse-data)\r
+  "Improve whitespace in a conditional/loop construct.\r
+Returns some position at the last line."\r
+  (interactive)\r
+  (or end\r
+      (setq end (point-max)))\r
+  (let ((ee (save-excursion (end-of-line) (point)))\r
+       (cperl-indent-region-fix-constructs\r
+        (or cperl-indent-region-fix-constructs 1))\r
+       p pp ml have-brace ret)\r
+    (save-excursion\r
+      (beginning-of-line)\r
+      (setq ret (point))\r
+      ;;  }? continue\r
+      ;;  blah; }\r
+      (if (not\r
+          (or (looking-at "[ \t]*\\(els\\(e\\|if\\)\\|continue\\|if\\|while\\|for\\(each\\)?\\|until\\)")\r
+              (setq have-brace (save-excursion (search-forward "}" ee t)))))\r
+         nil                           ; Do not need to do anything\r
+       ;; Looking at:\r
+       ;; }\r
+       ;; else\r
+       (if (and cperl-merge-trailing-else\r
+                (looking-at\r
+                 "[ \t]*}[ \t]*\n[ \t\n]*\\(els\\(e\\|if\\)\\|continue\\)\\>"))\r
+           (progn\r
+             (search-forward "}")\r
+             (setq p (point))\r
+             (skip-chars-forward " \t\n")\r
+             (delete-region p (point))\r
+             (insert (make-string cperl-indent-region-fix-constructs ?\ ))\r
+             (beginning-of-line)))\r
+       ;; Looking at:\r
+       ;; }     else\r
+       (if (looking-at "[ \t]*}\\(\t*\\|[ \t][ \t]+\\)\\<\\(els\\(e\\|if\\)\\|continue\\)\\>")\r
+           (progn\r
+             (search-forward "}")\r
+             (delete-horizontal-space)\r
+             (insert (make-string cperl-indent-region-fix-constructs ?\ ))\r
+             (beginning-of-line)))\r
+       ;; Looking at:\r
+       ;; else   {\r
+       (if (looking-at\r
+            "[ \t]*}?[ \t]*\\<\\(\\els\\(e\\|if\\)\\|continue\\|unless\\|if\\|while\\|for\\(each\\)?\\|until\\)\\>\\(\t*\\|[ \t][ \t]+\\)[^ \t\n#]")\r
+           (progn\r
+             (forward-word 1)\r
+             (delete-horizontal-space)\r
+             (insert (make-string cperl-indent-region-fix-constructs ?\ ))\r
+             (beginning-of-line)))\r
+       ;; Looking at:\r
+       ;; foreach my    $var\r
+       (if (looking-at\r
+            "[ \t]*\\<for\\(each\\)?[ \t]+\\(my\\|local\\|our\\)\\(\t*\\|[ \t][ \t]+\\)[^ \t\n]")\r
+           (progn\r
+             (forward-word 2)\r
+             (delete-horizontal-space)\r
+             (insert (make-string cperl-indent-region-fix-constructs ?\ ))\r
+             (beginning-of-line)))\r
+       ;; Looking at:\r
+       ;; foreach my $var     (\r
+       (if (looking-at\r
+            "[ \t]*\\<for\\(each\\)?[ \t]+\\(my\\|local\\|our\\)[ \t]*\\$[_a-zA-Z0-9]+\\(\t*\\|[ \t][ \t]+\\)[^ \t\n#]")\r
+           (progn\r
+             (forward-sexp 3)\r
+             (delete-horizontal-space)\r
+             (insert\r
+              (make-string cperl-indent-region-fix-constructs ?\ ))\r
+             (beginning-of-line)))\r
+       ;; Looking at:\r
+       ;; } foreach my $var ()    {\r
+       (if (looking-at\r
+            "[ \t]*\\(}[ \t]*\\)?\\<\\(\\els\\(e\\|if\\)\\|continue\\|if\\|unless\\|while\\|for\\(each\\)?\\(\\([ \t]+\\(my\\|local\\|our\\)\\)?[ \t]*\\$[_a-zA-Z0-9]+\\)?\\|until\\)\\>\\([ \t]*(\\|[ \t\n]*{\\)\\|[ \t]*{")\r
+           (progn\r
+             (setq ml (match-beginning 8))\r
+             (re-search-forward "[({]")\r
+             (forward-char -1)\r
+             (setq p (point))\r
+             (if (eq (following-char) ?\( )\r
+                 (progn\r
+                   (forward-sexp 1)\r
+                   (setq pp (point)))\r
+               ;; after `else' or nothing\r
+               (if ml                  ; after `else'\r
+                   (skip-chars-backward " \t\n")\r
+                 (beginning-of-line))\r
+               (setq pp nil))\r
+             ;; Now after the sexp before the brace\r
+             ;; Multiline expr should be special\r
+             (setq ml (and pp (save-excursion (goto-char p)\r
+                                              (search-forward "\n" pp t))))\r
+             (if (and (or (not pp) (< pp end))\r
+                      (looking-at "[ \t\n]*{"))\r
+                 (progn\r
+                   (cond\r
+                    ((bolp)            ; Were before `{', no if/else/etc\r
+                     nil)\r
+                    ((looking-at "\\(\t*\\| [ \t]+\\){")\r
+                     (delete-horizontal-space)\r
+                     (if (if ml\r
+                             cperl-extra-newline-before-brace-multiline\r
+                           cperl-extra-newline-before-brace)\r
+                         (progn\r
+                           (delete-horizontal-space)\r
+                           (insert "\n")\r
+                           (setq ret (point))\r
+                           (if (cperl-indent-line parse-data)\r
+                               (progn\r
+                                 (cperl-fix-line-spacing end parse-data)\r
+                                 (setq ret (point)))))\r
+                       (insert\r
+                        (make-string cperl-indent-region-fix-constructs ?\ ))))\r
+                    ((and (looking-at "[ \t]*\n")\r
+                          (not (if ml\r
+                                   cperl-extra-newline-before-brace-multiline\r
+                                 cperl-extra-newline-before-brace)))\r
+                     (setq pp (point))\r
+                     (skip-chars-forward " \t\n")\r
+                     (delete-region pp (point))\r
+                     (insert\r
+                      (make-string cperl-indent-region-fix-constructs ?\ ))))\r
+                   ;; Now we are before `{'\r
+                   (if (looking-at "[ \t\n]*{[ \t]*[^ \t\n#]")\r
+                       (progn\r
+                         (skip-chars-forward " \t\n")\r
+                         (setq pp (point))\r
+                         (forward-sexp 1)\r
+                         (setq p (point))\r
+                         (goto-char pp)\r
+                         (setq ml (search-forward "\n" p t))\r
+                         (if (or cperl-break-one-line-blocks-when-indent ml)\r
+                             ;; not good: multi-line BLOCK\r
+                             (progn\r
+                               (goto-char (1+ pp))\r
+                               (delete-horizontal-space)\r
+                               (insert "\n")\r
+                               (setq ret (point))\r
+                               (if (cperl-indent-line parse-data)\r
+                                   (setq ret (cperl-fix-line-spacing end parse-data)))))))))))\r
+       (beginning-of-line)\r
+       (setq p (point) pp (save-excursion (end-of-line) (point))) ; May be different from ee.\r
+       ;; Now check whether there is a hanging `}'\r
+       ;; Looking at:\r
+       ;; } blah\r
+       (if (and\r
+            cperl-fix-hanging-brace-when-indent\r
+            have-brace\r
+            (not (looking-at "[ \t]*}[ \t]*\\(\\<\\(els\\(if\\|e\\)\\|continue\\|while\\|until\\)\\>\\|$\\|#\\)"))\r
+            (condition-case nil\r
+                (progn\r
+                  (up-list 1)\r
+                  (if (and (<= (point) pp)\r
+                           (eq (preceding-char) ?\} )\r
+                           (cperl-after-block-and-statement-beg (point-min)))\r
+                      t\r
+                    (goto-char p)\r
+                    nil))\r
+              (error nil)))\r
+           (progn\r
+             (forward-char -1)\r
+             (skip-chars-backward " \t")\r
+             (if (bolp)\r
+                 ;; `}' was the first thing on the line, insert NL *after* it.\r
+                 (progn\r
+                   (cperl-indent-line parse-data)\r
+                   (search-forward "}")\r
+                   (delete-horizontal-space)\r
+                   (insert "\n"))\r
+               (delete-horizontal-space)\r
+               (or (eq (preceding-char) ?\;)\r
+                   (bolp)\r
+                   (and (eq (preceding-char) ?\} )\r
+                        (cperl-after-block-p (point-min)))\r
+                   (insert ";"))\r
+               (insert "\n")\r
+               (setq ret (point)))\r
+             (if (cperl-indent-line parse-data)\r
+                 (setq ret (cperl-fix-line-spacing end parse-data)))\r
+             (beginning-of-line)))))\r
+    ret))\r
+\r
+(defvar cperl-update-start)            ; Do not need to make them local\r
+(defvar cperl-update-end)\r
+(defun cperl-delay-update-hook (beg end old-len)\r
+  (setq cperl-update-start (min beg (or cperl-update-start (point-max))))\r
+  (setq cperl-update-end (max end (or cperl-update-end (point-min)))))\r
+\r
+(defun cperl-indent-region (start end)\r
+  "Simple variant of indentation of region in CPerl mode.\r
+Should be slow.  Will not indent comment if it starts at `comment-indent'\r
+or looks like continuation of the comment on the previous line.\r
+Indents all the lines whose first character is between START and END\r
+inclusive.\r
+\r
+If `cperl-indent-region-fix-constructs', will improve spacing on\r
+conditional/loop constructs."\r
+  (interactive "r")\r
+  (cperl-update-syntaxification end end)\r
+  (save-excursion\r
+    (let (cperl-update-start cperl-update-end (h-a-c after-change-functions))\r
+      (let ((indent-info (if cperl-emacs-can-parse\r
+                            (list nil nil nil) ; Cannot use '(), since will modify\r
+                          nil))\r
+           (pm 0) (imenu-scanning-message "Indenting... (%3d%%)")\r
+           after-change-functions      ; Speed it up!\r
+           st comm old-comm-indent new-comm-indent p pp i empty)\r
+       (if h-a-c (add-hook 'after-change-functions 'cperl-delay-update-hook))\r
+       (goto-char start)\r
+       (setq old-comm-indent (and (cperl-to-comment-or-eol)\r
+                                  (current-column))\r
+             new-comm-indent old-comm-indent)\r
+       (goto-char start)\r
+       (setq end (set-marker (make-marker) end)) ; indentation changes pos\r
+       (or (bolp) (beginning-of-line 2))\r
+       (or (fboundp 'imenu-progress-message)\r
+           (message "Indenting... For feedback load `imenu'..."))\r
+       (while (and (<= (point) end) (not (eobp))) ; bol to check start\r
+         (and (fboundp 'imenu-progress-message)\r
+              (imenu-progress-message\r
+               pm (/ (* 100 (- (point) start)) (- end start -1))))\r
+         (setq st (point))\r
+         (if (or\r
+              (setq empty (looking-at "[ \t]*\n"))\r
+              (and (setq comm (looking-at "[ \t]*#"))\r
+                   (or (eq (current-indentation) (or old-comm-indent\r
+                                                     comment-column))\r
+                       (setq old-comm-indent nil))))\r
+             (if (and old-comm-indent\r
+                      (not empty)\r
+                      (= (current-indentation) old-comm-indent)\r
+                      (not (eq (get-text-property (point) 'syntax-type) 'pod))\r
+                      (not (eq (get-text-property (point) 'syntax-table)\r
+                               cperl-st-cfence)))\r
+                 (let ((comment-column new-comm-indent))\r
+                   (indent-for-comment)))\r
+           (progn\r
+             (setq i (cperl-indent-line indent-info))\r
+             (or comm\r
+                 (not i)\r
+                 (progn\r
+                   (if cperl-indent-region-fix-constructs\r
+                       (goto-char (cperl-fix-line-spacing end indent-info)))\r
+                   (if (setq old-comm-indent\r
+                             (and (cperl-to-comment-or-eol)\r
+                                  (not (memq (get-text-property (point)\r
+                                                                'syntax-type)\r
+                                             '(pod here-doc)))\r
+                                  (not (eq (get-text-property (point)\r
+                                                              'syntax-table)\r
+                                           cperl-st-cfence))\r
+                                  (current-column)))\r
+                       (progn (indent-for-comment)\r
+                              (skip-chars-backward " \t")\r
+                              (skip-chars-backward "#")\r
+                              (setq new-comm-indent (current-column))))))))\r
+         (beginning-of-line 2))\r
+       (if (fboundp 'imenu-progress-message)\r
+           (imenu-progress-message pm 100)\r
+         (message nil)))\r
+      ;; Now run the update hooks\r
+      (and after-change-functions\r
+          cperl-update-end\r
+          (save-excursion\r
+            (goto-char cperl-update-end)\r
+            (insert " ")\r
+            (delete-char -1)\r
+            (goto-char cperl-update-start)\r
+            (insert " ")\r
+            (delete-char -1))))))\r
+\r
+;; Stolen from lisp-mode with a lot of improvements\r
+\r
+(defun cperl-fill-paragraph (&optional justify iteration)\r
+  "Like \\[fill-paragraph], but handle CPerl comments.\r
+If any of the current line is a comment, fill the comment or the\r
+block of it that point is in, preserving the comment's initial\r
+indentation and initial hashes.  Behaves usually outside of comment."\r
+  (interactive "P")\r
+  (let (;; Non-nil if the current line contains a comment.\r
+       has-comment\r
+\r
+       ;; If has-comment, the appropriate fill-prefix for the comment.\r
+       comment-fill-prefix\r
+       ;; Line that contains code and comment (or nil)\r
+       start\r
+       c spaces len dc (comment-column comment-column))\r
+    ;; Figure out what kind of comment we are looking at.\r
+    (save-excursion\r
+      (beginning-of-line)\r
+      (cond\r
+\r
+       ;; A line with nothing but a comment on it?\r
+       ((looking-at "[ \t]*#[# \t]*")\r
+       (setq has-comment t\r
+             comment-fill-prefix (buffer-substring (match-beginning 0)\r
+                                                   (match-end 0))))\r
+\r
+       ;; A line with some code, followed by a comment?  Remember that the\r
+       ;; semi which starts the comment shouldn't be part of a string or\r
+       ;; character.\r
+       ((cperl-to-comment-or-eol)\r
+       (setq has-comment t)\r
+       (looking-at "#+[ \t]*")\r
+       (setq start (point) c (current-column)\r
+             comment-fill-prefix\r
+             (concat (make-string (current-column) ?\ )\r
+                     (buffer-substring (match-beginning 0) (match-end 0)))\r
+             spaces (progn (skip-chars-backward " \t")\r
+                           (buffer-substring (point) start))\r
+             dc (- c (current-column)) len (- start (point))\r
+             start (point-marker))\r
+       (delete-char len)\r
+       (insert (make-string dc ?-)))))\r
+    (if (not has-comment)\r
+       (fill-paragraph justify)       ; Do the usual thing outside of comment\r
+      ;; Narrow to include only the comment, and then fill the region.\r
+      (save-restriction\r
+       (narrow-to-region\r
+        ;; Find the first line we should include in the region to fill.\r
+        (if start (progn (beginning-of-line) (point))\r
+          (save-excursion\r
+            (while (and (zerop (forward-line -1))\r
+                        (looking-at "^[ \t]*#+[ \t]*[^ \t\n#]")))\r
+            ;; We may have gone to far.  Go forward again.\r
+            (or (looking-at "^[ \t]*#+[ \t]*[^ \t\n#]")\r
+                (forward-line 1))\r
+            (point)))\r
+        ;; Find the beginning of the first line past the region to fill.\r
+        (save-excursion\r
+          (while (progn (forward-line 1)\r
+                        (looking-at "^[ \t]*#+[ \t]*[^ \t\n#]")))\r
+          (point)))\r
+       ;; Remove existing hashes\r
+       (goto-char (point-min))\r
+       (while (progn (forward-line 1) (< (point) (point-max)))\r
+         (skip-chars-forward " \t")\r
+         (and (looking-at "#+")\r
+              (delete-char (- (match-end 0) (match-beginning 0)))))\r
+\r
+       ;; Lines with only hashes on them can be paragraph boundaries.\r
+       (let ((paragraph-start (concat paragraph-start "\\|^[ \t#]*$"))\r
+             (paragraph-separate (concat paragraph-start "\\|^[ \t#]*$"))\r
+             (fill-prefix comment-fill-prefix))\r
+         (fill-paragraph justify)))\r
+      (if (and start)\r
+         (progn\r
+           (goto-char start)\r
+           (if (> dc 0)\r
+               (progn (delete-char dc) (insert spaces)))\r
+           (if (or (= (current-column) c) iteration) nil\r
+             (setq comment-column c)\r
+             (indent-for-comment)\r
+             ;; Repeat once more, flagging as iteration\r
+             (cperl-fill-paragraph justify t)))))))\r
+\r
+(defun cperl-do-auto-fill ()\r
+  ;; Break out if the line is short enough\r
+  (if (> (save-excursion\r
+          (end-of-line)\r
+          (current-column))\r
+        fill-column)\r
+      (let ((c (save-excursion (beginning-of-line)\r
+                              (cperl-to-comment-or-eol) (point)))\r
+           (s (memq (following-char) '(?\ ?\t))) marker)\r
+       (if (>= c (point)) nil\r
+         (setq marker (point-marker))\r
+         (cperl-fill-paragraph)\r
+         (goto-char marker)\r
+         ;; Is not enough, sometimes marker is a start of line\r
+         (if (bolp) (progn (re-search-forward "#+[ \t]*")\r
+                           (goto-char (match-end 0))))\r
+         ;; Following space could have gone:\r
+         (if (or (not s) (memq (following-char) '(?\ ?\t))) nil\r
+           (insert " ")\r
+           (backward-char 1))\r
+         ;; Previous space could have gone:\r
+         (or (memq (preceding-char) '(?\ ?\t)) (insert " "))))))\r
+\r
+(defun cperl-imenu-addback (lst &optional isback name)\r
+  ;; We suppose that the lst is a DAG, unless the first element only\r
+  ;; loops back, and ISBACK is set.  Thus this function cannot be\r
+  ;; applied twice without ISBACK set.\r
+  (cond ((not cperl-imenu-addback) lst)\r
+       (t\r
+        (or name\r
+            (setq name "+++BACK+++"))\r
+        (mapcar (lambda (elt)\r
+                  (if (and (listp elt) (listp (cdr elt)))\r
+                      (progn\r
+                        ;; In the other order it goes up\r
+                        ;; one level only ;-(\r
+                        (setcdr elt (cons (cons name lst)\r
+                                          (cdr elt)))\r
+                        (cperl-imenu-addback (cdr elt) t name))))\r
+                (if isback (cdr lst) lst))\r
+        lst)))\r
+\r
+(defun cperl-imenu--create-perl-index (&optional regexp)\r
+  (require 'cl)\r
+  (require 'imenu)                     ; May be called from TAGS creator\r
+  (let ((index-alist '()) (index-pack-alist '()) (index-pod-alist '())\r
+       (index-unsorted-alist '()) (i-s-f (default-value 'imenu-sort-function))\r
+       (index-meth-alist '()) meth\r
+       packages ends-ranges p marker\r
+       (prev-pos 0) char fchar index index1 name (end-range 0) package)\r
+    (goto-char (point-min))\r
+    (if noninteractive\r
+       (message "Scanning Perl for index")\r
+      (imenu-progress-message prev-pos 0))\r
+    (cperl-update-syntaxification (point-max) (point-max))\r
+    ;; Search for the function\r
+    (progn ;;save-match-data\r
+      (while (re-search-forward\r
+             (or regexp cperl-imenu--function-name-regexp-perl)\r
+             nil t)\r
+       (or noninteractive\r
+           (imenu-progress-message prev-pos))\r
+       (cond\r
+        ((and                          ; Skip some noise if building tags\r
+          (match-beginning 2)          ; package or sub\r
+          (eq (char-after (match-beginning 2)) ?p) ; package\r
+          (not (save-match-data\r
+                 (looking-at "[ \t\n]*;")))) ; Plain text word 'package'\r
+         nil)\r
+        ((and\r
+          (match-beginning 2)          ; package or sub\r
+          ;; Skip if quoted (will not skip multi-line ''-strings :-():\r
+          (null (get-text-property (match-beginning 1) 'syntax-table))\r
+          (null (get-text-property (match-beginning 1) 'syntax-type))\r
+          (null (get-text-property (match-beginning 1) 'in-pod)))\r
+         (save-excursion\r
+           (goto-char (match-beginning 2))\r
+           (setq fchar (following-char)))\r
+         ;; (if (looking-at "([^()]*)[ \t\n\f]*")\r
+         ;;    (goto-char (match-end 0)))      ; Messes what follows\r
+         (setq char (following-char)   ; ?\; for "sub foo () ;"\r
+               meth nil\r
+               p (point))\r
+         (while (and ends-ranges (>= p (car ends-ranges)))\r
+           ;; delete obsolete entries\r
+           (setq ends-ranges (cdr ends-ranges) packages (cdr packages)))\r
+         (setq package (or (car packages) "")\r
+               end-range (or (car ends-ranges) 0))\r
+         (if (eq fchar ?p)\r
+             (setq name (buffer-substring (match-beginning 3) (match-end 3))\r
+                   name (progn\r
+                          (set-text-properties 0 (length name) nil name)\r
+                          name)\r
+                   package (concat name "::")\r
+                   name (concat "package " name)\r
+                   end-range\r
+                   (save-excursion\r
+                     (parse-partial-sexp (point) (point-max) -1) (point))\r
+                   ends-ranges (cons end-range ends-ranges)\r
+                   packages (cons package packages)))\r
+         ;;   )\r
+         ;; Skip this function name if it is a prototype declaration.\r
+         (if (and (eq fchar ?s) (eq char ?\;)) nil\r
+           (setq name (buffer-substring (match-beginning 3) (match-end 3))\r
+                 marker (make-marker))\r
+           (set-text-properties 0 (length name) nil name)\r
+           (set-marker marker (match-end 3))\r
+           (if (eq fchar ?p)\r
+               (setq name (concat "package " name))\r
+             (cond ((string-match "[:']" name)\r
+                    (setq meth t))\r
+                   ((> p end-range) nil)\r
+                   (t\r
+                    (setq name (concat package name) meth t))))\r
+           (setq index (cons name marker))\r
+           (if (eq fchar ?p)\r
+               (push index index-pack-alist)\r
+             (push index index-alist))\r
+           (if meth (push index index-meth-alist))\r
+           (push index index-unsorted-alist)))\r
+        ((match-beginning 5)           ; POD section\r
+         ;; (beginning-of-line)\r
+         (setq index (imenu-example--name-and-position)\r
+               name (buffer-substring (match-beginning 6) (match-end 6)))\r
+         (set-text-properties 0 (length name) nil name)\r
+         (if (eq (char-after (match-beginning 5)) ?2)\r
+             (setq name (concat "   " name)))\r
+         (setcar index name)\r
+         (setq index1 (cons (concat "=" name) (cdr index)))\r
+         (push index index-pod-alist)\r
+         (push index1 index-unsorted-alist)))))\r
+    (or noninteractive\r
+       (imenu-progress-message prev-pos 100))\r
+    (setq index-alist\r
+         (if (default-value 'imenu-sort-function)\r
+             (sort index-alist (default-value 'imenu-sort-function))\r
+           (nreverse index-alist)))\r
+    (and index-pod-alist\r
+        (push (cons "+POD headers+..."\r
+                    (nreverse index-pod-alist))\r
+              index-alist))\r
+    (and (or index-pack-alist index-meth-alist)\r
+        (let ((lst index-pack-alist) hier-list pack elt group name)\r
+          ;; Remove "package ", reverse and uniquify.\r
+          (while lst\r
+            (setq elt (car lst) lst (cdr lst) name (substring (car elt) 8))\r
+            (if (assoc name hier-list) nil\r
+              (setq hier-list (cons (cons name (cdr elt)) hier-list))))\r
+          (setq lst index-meth-alist)\r
+          (while lst\r
+            (setq elt (car lst) lst (cdr lst))\r
+            (cond ((string-match "\\(::\\|'\\)[_a-zA-Z0-9]+$" (car elt))\r
+                   (setq pack (substring (car elt) 0 (match-beginning 0)))\r
+                   (if (setq group (assoc pack hier-list))\r
+                       (if (listp (cdr group))\r
+                           ;; Have some functions already\r
+                           (setcdr group\r
+                                   (cons (cons (substring\r
+                                                (car elt)\r
+                                                (+ 2 (match-beginning 0)))\r
+                                               (cdr elt))\r
+                                         (cdr group)))\r
+                         (setcdr group (list (cons (substring\r
+                                                    (car elt)\r
+                                                    (+ 2 (match-beginning 0)))\r
+                                                   (cdr elt)))))\r
+                     (setq hier-list\r
+                           (cons (cons pack\r
+                                       (list (cons (substring\r
+                                                    (car elt)\r
+                                                    (+ 2 (match-beginning 0)))\r
+                                                   (cdr elt))))\r
+                                 hier-list))))))\r
+          (push (cons "+Hierarchy+..."\r
+                      hier-list)\r
+                index-alist)))\r
+    (and index-pack-alist\r
+        (push (cons "+Packages+..."\r
+                    (nreverse index-pack-alist))\r
+              index-alist))\r
+    (and (or index-pack-alist index-pod-alist\r
+            (default-value 'imenu-sort-function))\r
+        index-unsorted-alist\r
+        (push (cons "+Unsorted List+..."\r
+                    (nreverse index-unsorted-alist))\r
+              index-alist))\r
+    (cperl-imenu-addback index-alist)))\r
+\r
+\f\r
+;; Suggested by Mark A. Hershberger\r
+(defun cperl-outline-level ()\r
+  (looking-at outline-regexp)\r
+  (cond ((not (match-beginning 1)) 0)  ; beginning-of-file\r
+       ((match-beginning 2)\r
+        (if (eq (char-after (match-beginning 2)) ?p)\r
+            0                          ; package\r
+          1))                          ; sub\r
+       ((match-beginning 5)\r
+        (if (eq (char-after (match-beginning 5)) ?1)\r
+            1                          ; head1\r
+          2))                          ; head2\r
+       (t 3)))                         ; should not happen\r
+\r
+\f\r
+(defvar cperl-compilation-error-regexp-alist\r
+  ;; This look like a paranoiac regexp: could anybody find a better one? (which WORK).\r
+  '(("^[^\n]* \\(file\\|at\\) \\([^ \t\n]+\\) [^\n]*line \\([0-9]+\\)[\\., \n]"\r
+     2 3))\r
+  "Alist that specifies how to match errors in perl output.")\r
+\r
+(if (fboundp 'eval-after-load)\r
+    (eval-after-load\r
+       "mode-compile"\r
+      '(setq perl-compilation-error-regexp-alist\r
+            cperl-compilation-error-regexp-alist)))\r
+\r
+\r
+(defun cperl-windowed-init ()\r
+  "Initialization under windowed version."\r
+  (if (or (featurep 'ps-print) cperl-faces-init)\r
+      ;; Need to init anyway:\r
+      (or cperl-faces-init (cperl-init-faces))\r
+    (add-hook 'font-lock-mode-hook\r
+             (function\r
+              (lambda ()\r
+                (if (memq major-mode '(perl-mode cperl-mode))\r
+                    (progn\r
+                      (or cperl-faces-init (cperl-init-faces)))))))\r
+    (if (fboundp 'eval-after-load)\r
+       (eval-after-load\r
+           "ps-print"\r
+         '(or cperl-faces-init (cperl-init-faces))))))\r
+\r
+(defun cperl-load-font-lock-keywords ()\r
+  (or cperl-faces-init (cperl-init-faces))\r
+  perl-font-lock-keywords)\r
+\r
+(defun cperl-load-font-lock-keywords-1 ()\r
+  (or cperl-faces-init (cperl-init-faces))\r
+  perl-font-lock-keywords-1)\r
+\r
+(defun cperl-load-font-lock-keywords-2 ()\r
+  (or cperl-faces-init (cperl-init-faces))\r
+  perl-font-lock-keywords-2)\r
+\r
+(defvar perl-font-lock-keywords-1 nil\r
+  "Additional expressions to highlight in Perl mode.  Minimal set.")\r
+(defvar perl-font-lock-keywords nil\r
+  "Additional expressions to highlight in Perl mode.  Default set.")\r
+(defvar perl-font-lock-keywords-2 nil\r
+  "Additional expressions to highlight in Perl mode.  Maximal set")\r
+\r
+(defvar font-lock-background-mode)\r
+(defvar font-lock-display-type)\r
+(defun cperl-init-faces-weak ()\r
+  ;; Allow `cperl-find-pods-heres' to run.\r
+  (or (boundp 'font-lock-constant-face)\r
+      (cperl-force-face font-lock-constant-face\r
+                        "Face for constant and label names")\r
+      ;;(setq font-lock-constant-face 'font-lock-constant-face)\r
+      ))\r
+\r
+(defun cperl-init-faces ()\r
+  (condition-case errs\r
+      (progn\r
+       (require 'font-lock)\r
+       (and (fboundp 'font-lock-fontify-anchored-keywords)\r
+            (featurep 'font-lock-extra)\r
+            (message "You have an obsolete package `font-lock-extra'.  Install `choose-color'."))\r
+       (let (t-font-lock-keywords t-font-lock-keywords-1 font-lock-anchored)\r
+         (if (fboundp 'font-lock-fontify-anchored-keywords)\r
+             (setq font-lock-anchored t))\r
+         (setq\r
+          t-font-lock-keywords\r
+          (list\r
+           (list "[ \t]+$" 0 cperl-invalid-face t)\r
+           (cons\r
+            (concat\r
+             "\\(^\\|[^$@%&\\]\\)\\<\\("\r
+             (mapconcat\r
+              'identity\r
+              '("if" "until" "while" "elsif" "else" "unless" "for"\r
+                "foreach" "continue" "exit" "die" "last" "goto" "next"\r
+                "redo" "return" "local" "exec" "sub" "do" "dump" "use"\r
+                "require" "package" "eval" "my" "BEGIN" "END" "CHECK" "INIT")\r
+              "\\|")                   ; Flow control\r
+             "\\)\\>") 2)              ; was "\\)[ \n\t;():,\|&]"\r
+                                       ; In what follows we use `type' style\r
+                                       ; for overwritable builtins\r
+           (list\r
+            (concat\r
+             "\\(^\\|[^$@%&\\]\\)\\<\\("\r
+             ;; "CORE" "__FILE__" "__LINE__" "abs" "accept" "alarm"\r
+             ;; "and" "atan2" "bind" "binmode" "bless" "caller"\r
+             ;; "chdir" "chmod" "chown" "chr" "chroot" "close"\r
+             ;; "closedir" "cmp" "connect" "continue" "cos" "crypt"\r
+             ;; "dbmclose" "dbmopen" "die" "dump" "endgrent"\r
+             ;; "endhostent" "endnetent" "endprotoent" "endpwent"\r
+             ;; "endservent" "eof" "eq" "exec" "exit" "exp" "fcntl"\r
+             ;; "fileno" "flock" "fork" "formline" "ge" "getc"\r
+             ;; "getgrent" "getgrgid" "getgrnam" "gethostbyaddr"\r
+             ;; "gethostbyname" "gethostent" "getlogin"\r
+             ;; "getnetbyaddr" "getnetbyname" "getnetent"\r
+             ;; "getpeername" "getpgrp" "getppid" "getpriority"\r
+             ;; "getprotobyname" "getprotobynumber" "getprotoent"\r
+             ;; "getpwent" "getpwnam" "getpwuid" "getservbyname"\r
+             ;; "getservbyport" "getservent" "getsockname"\r
+             ;; "getsockopt" "glob" "gmtime" "gt" "hex" "index" "int"\r
+             ;; "ioctl" "join" "kill" "lc" "lcfirst" "le" "length"\r
+             ;; "link" "listen" "localtime" "lock" "log" "lstat" "lt"\r
+             ;; "mkdir" "msgctl" "msgget" "msgrcv" "msgsnd" "ne"\r
+             ;; "not" "oct" "open" "opendir" "or" "ord" "pack" "pipe"\r
+             ;; "quotemeta" "rand" "read" "readdir" "readline"\r
+             ;; "readlink" "readpipe" "recv" "ref" "rename" "require"\r
+             ;; "reset" "reverse" "rewinddir" "rindex" "rmdir" "seek"\r
+             ;; "seekdir" "select" "semctl" "semget" "semop" "send"\r
+             ;; "setgrent" "sethostent" "setnetent" "setpgrp"\r
+             ;; "setpriority" "setprotoent" "setpwent" "setservent"\r
+             ;; "setsockopt" "shmctl" "shmget" "shmread" "shmwrite"\r
+             ;; "shutdown" "sin" "sleep" "socket" "socketpair"\r
+             ;; "sprintf" "sqrt" "srand" "stat" "substr" "symlink"\r
+             ;; "syscall" "sysopen" "sysread" "system" "syswrite" "tell"\r
+             ;; "telldir" "time" "times" "truncate" "uc" "ucfirst"\r
+             ;; "umask" "unlink" "unpack" "utime" "values" "vec"\r
+             ;; "wait" "waitpid" "wantarray" "warn" "write" "x" "xor"\r
+             "a\\(bs\\|ccept\\|tan2\\|larm\\|nd\\)\\|"\r
+             "b\\(in\\(d\\|mode\\)\\|less\\)\\|"\r
+             "c\\(h\\(r\\(\\|oot\\)\\|dir\\|mod\\|own\\)\\|aller\\|rypt\\|"\r
+             "lose\\(\\|dir\\)\\|mp\\|o\\(s\\|n\\(tinue\\|nect\\)\\)\\)\\|"\r
+             "CORE\\|d\\(ie\\|bm\\(close\\|open\\)\\|ump\\)\\|"\r
+             "e\\(x\\(p\\|it\\|ec\\)\\|q\\|nd\\(p\\(rotoent\\|went\\)\\|"\r
+             "hostent\\|servent\\|netent\\|grent\\)\\|of\\)\\|"\r
+             "f\\(ileno\\|cntl\\|lock\\|or\\(k\\|mline\\)\\)\\|"\r
+             "g\\(t\\|lob\\|mtime\\|e\\(\\|t\\(p\\(pid\\|r\\(iority\\|"\r
+             "oto\\(byn\\(ame\\|umber\\)\\|ent\\)\\)\\|eername\\|w"\r
+             "\\(uid\\|ent\\|nam\\)\\|grp\\)\\|host\\(by\\(addr\\|name\\)\\|"\r
+             "ent\\)\\|s\\(erv\\(by\\(port\\|name\\)\\|ent\\)\\|"\r
+             "ock\\(name\\|opt\\)\\)\\|c\\|login\\|net\\(by\\(addr\\|name\\)\\|"\r
+             "ent\\)\\|gr\\(ent\\|nam\\|gid\\)\\)\\)\\)\\|"\r
+             "hex\\|i\\(n\\(t\\|dex\\)\\|octl\\)\\|join\\|kill\\|"\r
+             "l\\(i\\(sten\\|nk\\)\\|stat\\|c\\(\\|first\\)\\|t\\|e"\r
+             "\\(\\|ngth\\)\\|o\\(c\\(altime\\|k\\)\\|g\\)\\)\\|m\\(sg\\(rcv\\|snd\\|"\r
+             "ctl\\|get\\)\\|kdir\\)\\|n\\(e\\|ot\\)\\|o\\(pen\\(\\|dir\\)\\|"\r
+             "r\\(\\|d\\)\\|ct\\)\\|p\\(ipe\\|ack\\)\\|quotemeta\\|"\r
+             "r\\(index\\|and\\|mdir\\|e\\(quire\\|ad\\(pipe\\|\\|lin"\r
+             "\\(k\\|e\\)\\|dir\\)\\|set\\|cv\\|verse\\|f\\|winddir\\|name"\r
+             "\\)\\)\\|s\\(printf\\|qrt\\|rand\\|tat\\|ubstr\\|e\\(t\\(p\\(r"\r
+             "\\(iority\\|otoent\\)\\|went\\|grp\\)\\|hostent\\|s\\(ervent\\|"\r
+             "ockopt\\)\\|netent\\|grent\\)\\|ek\\(\\|dir\\)\\|lect\\|"\r
+             "m\\(ctl\\|op\\|get\\)\\|nd\\)\\|h\\(utdown\\|m\\(read\\|ctl\\|"\r
+             "write\\|get\\)\\)\\|y\\(s\\(read\\|call\\|open\\|tem\\|write\\)\\|"\r
+             "mlink\\)\\|in\\|leep\\|ocket\\(pair\\|\\)\\)\\|t\\(runcate\\|"\r
+             "ell\\(\\|dir\\)\\|ime\\(\\|s\\)\\)\\|u\\(c\\(\\|first\\)\\|"\r
+             "time\\|mask\\|n\\(pack\\|link\\)\\)\\|v\\(alues\\|ec\\)\\|"\r
+             "w\\(a\\(rn\\|it\\(pid\\|\\)\\|ntarray\\)\\|rite\\)\\|"\r
+             "x\\(\\|or\\)\\|__\\(FILE__\\|LINE__\\|PACKAGE__\\)"\r
+             "\\)\\>") 2 'font-lock-type-face)\r
+           ;; In what follows we use `other' style\r
+           ;; for nonoverwritable builtins\r
+           ;; Somehow 's', 'm' are not auto-generated???\r
+           (list\r
+            (concat\r
+             "\\(^\\|[^$@%&\\]\\)\\<\\("\r
+             ;; "AUTOLOAD" "BEGIN" "CHECK" "DESTROY" "END" "INIT" "__END__" "chomp"\r
+             ;; "chop" "defined" "delete" "do" "each" "else" "elsif"\r
+             ;; "eval" "exists" "for" "foreach" "format" "goto"\r
+             ;; "grep" "if" "keys" "last" "local" "map" "my" "next"\r
+             ;; "no" "package" "pop" "pos" "print" "printf" "push"\r
+             ;; "q" "qq" "qw" "qx" "redo" "return" "scalar" "shift"\r
+             ;; "sort" "splice" "split" "study" "sub" "tie" "tr"\r
+             ;; "undef" "unless" "unshift" "untie" "until" "use"\r
+             ;; "while" "y"\r
+             "AUTOLOAD\\|BEGIN\\|CHECK\\|cho\\(p\\|mp\\)\\|d\\(e\\(fined\\|lete\\)\\|"\r
+             "o\\)\\|DESTROY\\|e\\(ach\\|val\\|xists\\|ls\\(e\\|if\\)\\)\\|"\r
+             "END\\|for\\(\\|each\\|mat\\)\\|g\\(rep\\|oto\\)\\|INIT\\|if\\|keys\\|"\r
+             "l\\(ast\\|ocal\\)\\|m\\(ap\\|y\\)\\|n\\(ext\\|o\\)\\|our\\|"\r
+             "p\\(ackage\\|rint\\(\\|f\\)\\|ush\\|o\\(p\\|s\\)\\)\\|"\r
+             "q\\(\\|q\\|w\\|x\\|r\\)\\|re\\(turn\\|do\\)\\|s\\(pli\\(ce\\|t\\)\\|"\r
+             "calar\\|tudy\\|ub\\|hift\\|ort\\)\\|t\\(r\\|ie\\)\\|"\r
+             "u\\(se\\|n\\(shift\\|ti\\(l\\|e\\)\\|def\\|less\\)\\)\\|"\r
+             "while\\|y\\|__\\(END\\|DATA\\)__" ;__DATA__ added manually\r
+             "\\|[sm]"                 ; Added manually\r
+             "\\)\\>") 2 'cperl-nonoverridable-face)\r
+           ;;          (mapconcat 'identity\r
+           ;;                     '("#endif" "#else" "#ifdef" "#ifndef" "#if"\r
+           ;;                       "#include" "#define" "#undef")\r
+           ;;                     "\\|")\r
+           '("-[rwxoRWXOezsfdlpSbctugkTBMAC]\\>\\([ \t]+_\\>\\)?" 0\r
+             font-lock-function-name-face keep) ; Not very good, triggers at "[a-z]"\r
+           '("\\<sub[ \t]+\\([^ \t{;()]+\\)[ \t]*\\(([^()]*)[ \t]*\\)?[#{\n]" 1\r
+             font-lock-function-name-face)\r
+           '("\\<\\(package\\|require\\|use\\|import\\|no\\|bootstrap\\)[ \t]+\\([a-zA-z_][a-zA-z_0-9:]*\\)[ \t;]" ; require A if B;\r
+             2 font-lock-function-name-face)\r
+           '("^[ \t]*format[ \t]+\\([a-zA-z_][a-zA-z_0-9:]*\\)[ \t]*=[ \t]*$"\r
+             1 font-lock-function-name-face)\r
+           (cond ((featurep 'font-lock-extra)\r
+                  '("\\([]}\\\\%@>*&]\\|\\$[a-zA-Z0-9_:]*\\)[ \t]*{[ \t]*\\(-?[a-zA-Z0-9_:]+\\)[ \t]*}"\r
+                    (2 font-lock-string-face t)\r
+                    (0 '(restart 2 t)))) ; To highlight $a{bc}{ef}\r
+                 (font-lock-anchored\r
+                  '("\\([]}\\\\%@>*&]\\|\\$[a-zA-Z0-9_:]*\\)[ \t]*{[ \t]*\\(-?[a-zA-Z0-9_:]+\\)[ \t]*}"\r
+                    (2 font-lock-string-face t)\r
+                    ("\\=[ \t]*{[ \t]*\\(-?[a-zA-Z0-9_:]+\\)[ \t]*}"\r
+                     nil nil\r
+                     (1 font-lock-string-face t))))\r
+                 (t '("\\([]}\\\\%@>*&]\\|\\$[a-zA-Z0-9_:]*\\)[ \t]*{[ \t]*\\(-?[a-zA-Z0-9_:]+\\)[ \t]*}"\r
+                      2 font-lock-string-face t)))\r
+           '("[\[ \t{,(]\\(-?[a-zA-Z0-9_:]+\\)[ \t]*=>" 1\r
+             font-lock-string-face t)\r
+           '("^[ \t]*\\([a-zA-Z0-9_]+[ \t]*:\\)[ \t]*\\($\\|{\\|\\<\\(until\\|while\\|for\\(each\\)?\\|do\\)\\>\\)" 1\r
+             font-lock-constant-face)  ; labels\r
+           '("\\<\\(continue\\|next\\|last\\|redo\\|goto\\)\\>[ \t]+\\([a-zA-Z0-9_:]+\\)" ; labels as targets\r
+             2 font-lock-constant-face)\r
+           ;; Uncomment to get perl-mode-like vars\r
+            ;;; '("[$*]{?\\(\\sw+\\)" 1 font-lock-variable-name-face)\r
+            ;;; '("\\([@%]\\|\\$#\\)\\(\\sw+\\)"\r
+            ;;;  (2 (cons font-lock-variable-name-face '(underline))))\r
+           (cond ((featurep 'font-lock-extra)\r
+                  '("^[ \t]*\\(my\\|local\\|our\\)[ \t]*\\(([ \t]*\\)?\\([$@%*][a-zA-Z0-9_:]+\\)\\([ \t]*,\\)?"\r
+                    (3 font-lock-variable-name-face)\r
+                    (4 '(another 4 nil\r
+                                 ("\\=[ \t]*,[ \t]*\\([$@%*][a-zA-Z0-9_:]+\\)\\([ \t]*,\\)?"\r
+                                  (1 font-lock-variable-name-face)\r
+                                  (2 '(restart 2 nil) nil t)))\r
+                       nil t)))        ; local variables, multiple\r
+                 (font-lock-anchored\r
+                  '("^[ \t{}]*\\(my\\|local\\|our\\)[ \t]*\\(([ \t]*\\)?\\([$@%*][a-zA-Z0-9_:]+\\)"\r
+                    (3 font-lock-variable-name-face)\r
+                    ("\\=[ \t]*,[ \t]*\\([$@%*][a-zA-Z0-9_:]+\\)"\r
+                     nil nil\r
+                     (1 font-lock-variable-name-face))))\r
+                 (t '("^[ \t{}]*\\(my\\|local\\our\\)[ \t]*\\(([ \t]*\\)?\\([$@%*][a-zA-Z0-9_:]+\\)"\r
+                      3 font-lock-variable-name-face)))\r
+           '("\\<for\\(each\\)?\\([ \t]+\\(my\\|local\\|our\\)\\)?[ \t]*\\(\\$[a-zA-Z_][a-zA-Z_0-9]*\\)[ \t]*("\r
+             4 font-lock-variable-name-face)))\r
+         (setq\r
+          t-font-lock-keywords-1\r
+          (and (fboundp 'turn-on-font-lock) ; Check for newer font-lock\r
+               (not cperl-xemacs-p)    ; not yet as of XEmacs 19.12\r
+               '(\r
+                 ("\\(\\([@%]\\|\$#\\)[a-zA-Z_:][a-zA-Z0-9_:]*\\)" 1\r
+                  (if (eq (char-after (match-beginning 2)) ?%)\r
+                      cperl-hash-face\r
+                    cperl-array-face)\r
+                  t)                   ; arrays and hashes\r
+                 ("\\(\\([$@]+\\)[a-zA-Z_:][a-zA-Z0-9_:]*\\)[ \t]*\\([[{]\\)"\r
+                  1\r
+                  (if (= (- (match-end 2) (match-beginning 2)) 1)\r
+                      (if (eq (char-after (match-beginning 3)) ?{)\r
+                          cperl-hash-face\r
+                        cperl-array-face) ; arrays and hashes\r
+                    font-lock-variable-name-face) ; Just to put something\r
+                  t)\r
+                 ;;("\\([smy]\\|tr\\)\\([^a-z_A-Z0-9]\\)\\(\\([^\n\\]*||\\)\\)\\2")\r
+                      ;;; Too much noise from \s* @s[ and friends\r
+                 ;;("\\(\\<\\([msy]\\|tr\\)[ \t]*\\([^ \t\na-zA-Z0-9_]\\)\\|\\(/\\)\\)"\r
+                 ;;(3 font-lock-function-name-face t t)\r
+                 ;;(4\r
+                 ;; (if (cperl-slash-is-regexp)\r
+                 ;;    font-lock-function-name-face 'default) nil t))\r
+                 )))\r
+         (if cperl-highlight-variables-indiscriminately\r
+             (setq t-font-lock-keywords-1\r
+                   (append t-font-lock-keywords-1\r
+                           (list '("[$*]{?\\(\\sw+\\)" 1\r
+                                   font-lock-variable-name-face)))))\r
+         (setq perl-font-lock-keywords-1 \r
+               (if cperl-syntaxify-by-font-lock\r
+                   (cons 'cperl-fontify-update\r
+                         t-font-lock-keywords)\r
+                 t-font-lock-keywords)\r
+               perl-font-lock-keywords perl-font-lock-keywords-1\r
+               perl-font-lock-keywords-2 (append\r
+                                          perl-font-lock-keywords-1\r
+                                          t-font-lock-keywords-1)))\r
+       (if (fboundp 'ps-print-buffer) (cperl-ps-print-init))\r
+       (if (or (featurep 'choose-color) (featurep 'font-lock-extra))\r
+           (eval                       ; Avoid a warning\r
+            '(font-lock-require-faces\r
+              (list\r
+               ;; Color-light    Color-dark      Gray-light      Gray-dark Mono\r
+               (list 'font-lock-comment-face\r
+                     ["Firebrick"      "OrangeRed"     "DimGray"       "Gray80"]\r
+                     nil\r
+                     [nil              nil             t               t       t]\r
+                     [nil              nil             t               t       t]\r
+                     nil)\r
+               (list 'font-lock-string-face\r
+                     ["RosyBrown"      "LightSalmon"   "Gray50"        "LightGray"]\r
+                     nil\r
+                     nil\r
+                     [nil              nil             t               t       t]\r
+                     nil)\r
+               (list 'font-lock-function-name-face\r
+                     (vector\r
+                      "Blue"           "LightSkyBlue"  "Gray50"        "LightGray"\r
+                      (cdr (assq 'background-color ; if mono\r
+                                 (frame-parameters))))\r
+                     (vector\r
+                      nil              nil             nil             nil\r
+                      (cdr (assq 'foreground-color ; if mono\r
+                                 (frame-parameters))))\r
+                     [nil              nil             t               t       t]\r
+                     nil\r
+                     nil)\r
+               (list 'font-lock-variable-name-face\r
+                     ["DarkGoldenrod"  "LightGoldenrod" "DimGray"      "Gray90"]\r
+                     nil\r
+                     [nil              nil             t               t       t]\r
+                     [nil              nil             t               t       t]\r
+                     nil)\r
+               (list 'font-lock-type-face\r
+                     ["DarkOliveGreen" "PaleGreen"     "DimGray"       "Gray80"]\r
+                     nil\r
+                     [nil              nil             t               t       t]\r
+                     nil\r
+                     [nil              nil             t               t       t])\r
+               (list 'font-lock-constant-face\r
+                     ["CadetBlue"      "Aquamarine"    "Gray50"        "LightGray"]\r
+                     nil\r
+                     [nil              nil             t               t       t]\r
+                     nil\r
+                     [nil              nil             t               t       t])\r
+               (list 'cperl-nonoverridable-face\r
+                     ["chartreuse3"    ("orchid1" "orange")\r
+                      nil              "Gray80"]\r
+                     [nil              nil             "gray90"]\r
+                     [nil              nil             nil             t       t]\r
+                     [nil              nil             t               t]\r
+                     [nil              nil             t               t       t])\r
+               (list 'cperl-array-face\r
+                     ["blue"           "yellow"        nil             "Gray80"]\r
+                     ["lightyellow2"   ("navy" "os2blue" "darkgreen")\r
+                      "gray90"]\r
+                     t\r
+                     nil\r
+                     nil)\r
+               (list 'cperl-hash-face\r
+                     ["red"            "red"           nil             "Gray80"]\r
+                     ["lightyellow2"   ("navy" "os2blue" "darkgreen")\r
+                      "gray90"]\r
+                     t\r
+                     t\r
+                     nil))))\r
+         ;; Do it the dull way, without choose-color\r
+         (defvar cperl-guessed-background nil\r
+           "Display characteristics as guessed by cperl.")\r
+         ;;      (or (fboundp 'x-color-defined-p)\r
+         ;;          (defalias 'x-color-defined-p \r
+         ;;            (cond ((fboundp 'color-defined-p) 'color-defined-p)\r
+         ;;                  ;; XEmacs >= 19.12\r
+         ;;                  ((fboundp 'valid-color-name-p) 'valid-color-name-p)\r
+         ;;                  ;; XEmacs 19.11\r
+         ;;                  (t 'x-valid-color-name-p))))\r
+         (cperl-force-face font-lock-constant-face\r
+                           "Face for constant and label names")\r
+         (cperl-force-face font-lock-variable-name-face\r
+                           "Face for variable names")\r
+         (cperl-force-face font-lock-type-face\r
+                           "Face for data types")\r
+         (cperl-force-face cperl-nonoverridable-face\r
+                           "Face for data types from another group")\r
+         (cperl-force-face font-lock-comment-face\r
+                           "Face for comments")\r
+         (cperl-force-face font-lock-function-name-face\r
+                           "Face for function names")\r
+         (cperl-force-face cperl-hash-face\r
+                           "Face for hashes")\r
+         (cperl-force-face cperl-array-face\r
+                           "Face for arrays")\r
+         ;;(defvar font-lock-constant-face 'font-lock-constant-face)\r
+         ;;(defvar font-lock-variable-name-face 'font-lock-variable-name-face)\r
+         ;;(or (boundp 'font-lock-type-face)\r
+         ;;    (defconst font-lock-type-face\r
+         ;;    'font-lock-type-face\r
+         ;;    "Face to use for data types."))\r
+         ;;(or (boundp 'cperl-nonoverridable-face)\r
+         ;;    (defconst cperl-nonoverridable-face\r
+         ;;    'cperl-nonoverridable-face\r
+         ;;    "Face to use for data types from another group."))\r
+         ;;(if (not cperl-xemacs-p) nil\r
+         ;;  (or (boundp 'font-lock-comment-face)\r
+         ;;    (defconst font-lock-comment-face\r
+         ;;      'font-lock-comment-face\r
+         ;;      "Face to use for comments."))\r
+         ;;  (or (boundp 'font-lock-keyword-face)\r
+         ;;    (defconst font-lock-keyword-face\r
+         ;;      'font-lock-keyword-face\r
+         ;;      "Face to use for keywords."))\r
+         ;;  (or (boundp 'font-lock-function-name-face)\r
+         ;;    (defconst font-lock-function-name-face\r
+         ;;      'font-lock-function-name-face\r
+         ;;      "Face to use for function names.")))\r
+         (if (and\r
+              (not (cperl-is-face 'cperl-array-face))\r
+              (cperl-is-face 'font-lock-emphasized-face))\r
+             (copy-face 'font-lock-emphasized-face 'cperl-array-face))\r
+         (if (and\r
+              (not (cperl-is-face 'cperl-hash-face))\r
+              (cperl-is-face 'font-lock-other-emphasized-face))\r
+             (copy-face 'font-lock-other-emphasized-face\r
+                        'cperl-hash-face))\r
+         (if (and\r
+              (not (cperl-is-face 'cperl-nonoverridable-face))\r
+              (cperl-is-face 'font-lock-other-type-face))\r
+             (copy-face 'font-lock-other-type-face\r
+                        'cperl-nonoverridable-face))\r
+         ;;(or (boundp 'cperl-hash-face)\r
+         ;;    (defconst cperl-hash-face\r
+         ;;    'cperl-hash-face\r
+         ;;    "Face to use for hashes."))\r
+         ;;(or (boundp 'cperl-array-face)\r
+         ;;    (defconst cperl-array-face\r
+         ;;    'cperl-array-face\r
+         ;;    "Face to use for arrays."))\r
+         ;; Here we try to guess background\r
+         (let ((background\r
+                (if (boundp 'font-lock-background-mode)\r
+                    font-lock-background-mode\r
+                  'light))\r
+               (face-list (and (fboundp 'face-list) (face-list))))\r
+;;;;       (fset 'cperl-is-face\r
+;;;;             (cond ((fboundp 'find-face)\r
+;;;;                    (symbol-function 'find-face))\r
+;;;;                   (face-list\r
+;;;;                    (function (lambda (face) (member face face-list))))\r
+;;;;                   (t\r
+;;;;                    (function (lambda (face) (boundp face))))))\r
+           (defvar cperl-guessed-background\r
+             (if (and (boundp 'font-lock-display-type)\r
+                      (eq font-lock-display-type 'grayscale))\r
+                 'gray\r
+               background)\r
+             "Background as guessed by CPerl mode")\r
+           (and (not (cperl-is-face 'font-lock-constant-face))\r
+                (cperl-is-face 'font-lock-reference-face)\r
+                (copy-face 'font-lock-reference-face 'font-lock-constant-face))\r
+           (if (cperl-is-face 'font-lock-type-face) nil\r
+             (copy-face 'default 'font-lock-type-face)\r
+             (cond\r
+              ((eq background 'light)\r
+               (set-face-foreground 'font-lock-type-face\r
+                                    (if (x-color-defined-p "seagreen")\r
+                                        "seagreen"\r
+                                      "sea green")))\r
+              ((eq background 'dark)\r
+               (set-face-foreground 'font-lock-type-face\r
+                                    (if (x-color-defined-p "os2pink")\r
+                                        "os2pink"\r
+                                      "pink")))\r
+              (t\r
+               (set-face-background 'font-lock-type-face "gray90"))))\r
+           (if (cperl-is-face 'cperl-nonoverridable-face)\r
+               nil\r
+             (copy-face 'font-lock-type-face 'cperl-nonoverridable-face)\r
+             (cond\r
+              ((eq background 'light)\r
+               (set-face-foreground 'cperl-nonoverridable-face\r
+                                    (if (x-color-defined-p "chartreuse3")\r
+                                        "chartreuse3"\r
+                                      "chartreuse")))\r
+              ((eq background 'dark)\r
+               (set-face-foreground 'cperl-nonoverridable-face\r
+                                    (if (x-color-defined-p "orchid1")\r
+                                        "orchid1"\r
+                                      "orange")))))\r
+;;;        (if (cperl-is-face 'font-lock-other-emphasized-face) nil\r
+;;;          (copy-face 'bold-italic 'font-lock-other-emphasized-face)\r
+;;;          (cond\r
+;;;           ((eq background 'light)\r
+;;;            (set-face-background 'font-lock-other-emphasized-face\r
+;;;                                 (if (x-color-defined-p "lightyellow2")\r
+;;;                                     "lightyellow2"\r
+;;;                                   (if (x-color-defined-p "lightyellow")\r
+;;;                                       "lightyellow"\r
+;;;                                     "light yellow"))))\r
+;;;           ((eq background 'dark)\r
+;;;            (set-face-background 'font-lock-other-emphasized-face\r
+;;;                                 (if (x-color-defined-p "navy")\r
+;;;                                     "navy"\r
+;;;                                   (if (x-color-defined-p "darkgreen")\r
+;;;                                       "darkgreen"\r
+;;;                                     "dark green"))))\r
+;;;           (t (set-face-background 'font-lock-other-emphasized-face "gray90"))))\r
+;;;        (if (cperl-is-face 'font-lock-emphasized-face) nil\r
+;;;          (copy-face 'bold 'font-lock-emphasized-face)\r
+;;;          (cond\r
+;;;           ((eq background 'light)\r
+;;;            (set-face-background 'font-lock-emphasized-face\r
+;;;                                 (if (x-color-defined-p "lightyellow2")\r
+;;;                                     "lightyellow2"\r
+;;;                                   "lightyellow")))\r
+;;;           ((eq background 'dark)\r
+;;;            (set-face-background 'font-lock-emphasized-face\r
+;;;                                 (if (x-color-defined-p "navy")\r
+;;;                                     "navy"\r
+;;;                                   (if (x-color-defined-p "darkgreen")\r
+;;;                                       "darkgreen"\r
+;;;                                     "dark green"))))\r
+;;;           (t (set-face-background 'font-lock-emphasized-face "gray90"))))\r
+           (if (cperl-is-face 'font-lock-variable-name-face) nil\r
+             (copy-face 'italic 'font-lock-variable-name-face))\r
+           (if (cperl-is-face 'font-lock-constant-face) nil\r
+             (copy-face 'italic 'font-lock-constant-face))))\r
+       (setq cperl-faces-init t))\r
+    (error (message "cperl-init-faces (ignored): %s" errs))))\r
+\r
+\r
+(defun cperl-ps-print-init ()\r
+  "Initialization of `ps-print' components for faces used in CPerl."\r
+  (eval-after-load "ps-print"\r
+    '(setq ps-bold-faces\r
+          ;;                   font-lock-variable-name-face\r
+          ;;                   font-lock-constant-face\r
+          (append '(cperl-array-face\r
+                    cperl-hash-face)\r
+                  ps-bold-faces)\r
+          ps-italic-faces\r
+          ;;                   font-lock-constant-face\r
+          (append '(cperl-nonoverridable-face\r
+                    cperl-hash-face)\r
+                  ps-italic-faces)\r
+          ps-underlined-faces\r
+          ;;        font-lock-type-face\r
+          (append '(cperl-array-face\r
+                    cperl-hash-face\r
+                    underline\r
+                    cperl-nonoverridable-face)\r
+                  ps-underlined-faces))))\r
+\r
+(defvar ps-print-face-extension-alist)\r
+\r
+(defun cperl-ps-print (&optional file)\r
+  "Pretty-print in CPerl style.\r
+If optional argument FILE is an empty string, prints to printer, otherwise\r
+to the file FILE.  If FILE is nil, prompts for a file name.\r
+\r
+Style of printout regulated by the variable `cperl-ps-print-face-properties'."\r
+  (interactive)\r
+  (or file\r
+      (setq file (read-from-minibuffer\r
+                 "Print to file (if empty - to printer): "\r
+                 (concat (buffer-file-name) ".ps")\r
+                 nil nil 'file-name-history)))\r
+  (or (> (length file) 0)\r
+      (setq file nil))\r
+  (require 'ps-print)                  ; To get ps-print-face-extension-alist\r
+  (let ((ps-print-color-p t)\r
+       (ps-print-face-extension-alist ps-print-face-extension-alist))\r
+    (cperl-ps-extend-face-list cperl-ps-print-face-properties)\r
+    (ps-print-buffer-with-faces file)))\r
+\r
+;;; (defun cperl-ps-print-init ()\r
+;;;   "Initialization of `ps-print' components for faces used in CPerl."\r
+;;;   ;; Guard against old versions\r
+;;;   (defvar ps-underlined-faces nil)\r
+;;;   (defvar ps-bold-faces nil)\r
+;;;   (defvar ps-italic-faces nil)\r
+;;;   (setq ps-bold-faces\r
+;;;    (append '(font-lock-emphasized-face\r
+;;;              cperl-array-face\r
+;;;              font-lock-keyword-face\r
+;;;              font-lock-variable-name-face\r
+;;;              font-lock-constant-face\r
+;;;              font-lock-reference-face\r
+;;;              font-lock-other-emphasized-face\r
+;;;              cperl-hash-face)\r
+;;;            ps-bold-faces))\r
+;;;   (setq ps-italic-faces\r
+;;;    (append '(cperl-nonoverridable-face\r
+;;;              font-lock-constant-face\r
+;;;              font-lock-reference-face\r
+;;;              font-lock-other-emphasized-face\r
+;;;              cperl-hash-face)\r
+;;;            ps-italic-faces))\r
+;;;   (setq ps-underlined-faces\r
+;;;    (append '(font-lock-emphasized-face\r
+;;;              cperl-array-face\r
+;;;              font-lock-other-emphasized-face\r
+;;;              cperl-hash-face\r
+;;;              cperl-nonoverridable-face font-lock-type-face)\r
+;;;            ps-underlined-faces))\r
+;;;   (cons 'font-lock-type-face ps-underlined-faces))\r
+\r
+\r
+(if (cperl-enable-font-lock) (cperl-windowed-init))\r
+\r
+(defconst cperl-styles-entries\r
+  '(cperl-indent-level cperl-brace-offset cperl-continued-brace-offset\r
+    cperl-label-offset cperl-extra-newline-before-brace\r
+    cperl-merge-trailing-else\r
+    cperl-continued-statement-offset))\r
+\r
+(defconst cperl-style-alist\r
+  '(("CPerl"                        ; =GNU without extra-newline-before-brace\r
+     (cperl-indent-level               .  2)\r
+     (cperl-brace-offset               .  0)\r
+     (cperl-continued-brace-offset     .  0)\r
+     (cperl-label-offset               . -2)\r
+     (cperl-extra-newline-before-brace .  nil)\r
+     (cperl-merge-trailing-else               .  t)\r
+     (cperl-continued-statement-offset .  2))\r
+    ("PerlStyle"                       ; CPerl with 4 as indent\r
+     (cperl-indent-level               .  4)\r
+     (cperl-brace-offset               .  0)\r
+     (cperl-continued-brace-offset     .  0)\r
+     (cperl-label-offset               . -4)\r
+     (cperl-extra-newline-before-brace .  nil)\r
+     (cperl-merge-trailing-else               .  t)\r
+     (cperl-continued-statement-offset .  4))\r
+    ("GNU"\r
+     (cperl-indent-level               .  2)\r
+     (cperl-brace-offset               .  0)\r
+     (cperl-continued-brace-offset     .  0)\r
+     (cperl-label-offset               . -2)\r
+     (cperl-extra-newline-before-brace .  t)\r
+     (cperl-merge-trailing-else               .  nil)\r
+     (cperl-continued-statement-offset .  2))\r
+    ("K&R"\r
+     (cperl-indent-level               .  5)\r
+     (cperl-brace-offset               .  0)\r
+     (cperl-continued-brace-offset     . -5)\r
+     (cperl-label-offset               . -5)\r
+     ;;(cperl-extra-newline-before-brace .  nil) ; ???\r
+     (cperl-merge-trailing-else               .  nil)\r
+     (cperl-continued-statement-offset .  5))\r
+    ("BSD"\r
+     (cperl-indent-level               .  4)\r
+     (cperl-brace-offset               .  0)\r
+     (cperl-continued-brace-offset     . -4)\r
+     (cperl-label-offset               . -4)\r
+     ;;(cperl-extra-newline-before-brace .  nil) ; ???\r
+     (cperl-continued-statement-offset .  4))\r
+    ("C++"\r
+     (cperl-indent-level               .  4)\r
+     (cperl-brace-offset               .  0)\r
+     (cperl-continued-brace-offset     . -4)\r
+     (cperl-label-offset               . -4)\r
+     (cperl-continued-statement-offset .  4)\r
+     (cperl-merge-trailing-else               .  nil)\r
+     (cperl-extra-newline-before-brace .  t))\r
+    ("Current")\r
+    ("Whitesmith"\r
+     (cperl-indent-level               .  4)\r
+     (cperl-brace-offset               .  0)\r
+     (cperl-continued-brace-offset     .  0)\r
+     (cperl-label-offset               . -4)\r
+     ;;(cperl-extra-newline-before-brace .  nil) ; ???\r
+     (cperl-continued-statement-offset .  4)))\r
+  "(Experimental) list of variables to set to get a particular indentation style.\r
+Should be used via `cperl-set-style' or via Perl menu.")\r
+\r
+(defun cperl-set-style (style)\r
+  "Set CPerl mode variables to use one of several different indentation styles.\r
+The arguments are a string representing the desired style.\r
+The list of styles is in `cperl-style-alist', available styles\r
+are GNU, K&R, BSD, C++ and Whitesmith.\r
+\r
+The current value of style is memorized (unless there is a memorized\r
+data already), may be restored by `cperl-set-style-back'.\r
+\r
+Chosing \"Current\" style will not change style, so this may be used for\r
+side-effect of memorizing only."\r
+  (interactive\r
+   (let ((list (mapcar (function (lambda (elt) (list (car elt)))) \r
+                      cperl-style-alist)))\r
+     (list (completing-read "Enter style: " list nil 'insist))))\r
+  (or cperl-old-style\r
+      (setq cperl-old-style\r
+           (mapcar (function\r
+                    (lambda (name)\r
+                      (cons name (eval name))))\r
+                   cperl-styles-entries)))\r
+  (let ((style (cdr (assoc style cperl-style-alist))) setting str sym)\r
+    (while style\r
+      (setq setting (car style) style (cdr style))\r
+      (set (car setting) (cdr setting)))))\r
+\r
+(defun cperl-set-style-back ()\r
+  "Restore a style memorised by `cperl-set-style'."\r
+  (interactive)\r
+  (or cperl-old-style (error "The style was not changed"))\r
+  (let (setting)\r
+    (while cperl-old-style\r
+      (setq setting (car cperl-old-style)\r
+           cperl-old-style (cdr cperl-old-style))\r
+      (set (car setting) (cdr setting)))))\r
+\r
+(defun cperl-check-syntax ()\r
+  (interactive)\r
+  (require 'mode-compile)\r
+  (let ((perl-dbg-flags (concat cperl-extra-perl-args " -wc")))\r
+    (eval '(mode-compile))))           ; Avoid a warning\r
+\r
+(defun cperl-info-buffer (type)\r
+  ;; Returns buffer with documentation.  Creates if missing.\r
+  ;; If TYPE, this vars buffer.\r
+  ;; Special care is taken to not stomp over an existing info buffer\r
+  (let* ((bname (if type "*info-perl-var*" "*info-perl*"))\r
+        (info (get-buffer bname))\r
+        (oldbuf (get-buffer "*info*")))\r
+    (if info info\r
+      (save-window-excursion\r
+       ;; Get Info running\r
+       (require 'info)\r
+       (cond (oldbuf\r
+              (set-buffer oldbuf)\r
+              (rename-buffer "*info-perl-tmp*")))\r
+       (save-window-excursion\r
+         (info))\r
+       (Info-find-node cperl-info-page (if type "perlvar" "perlfunc"))\r
+       (set-buffer "*info*")\r
+       (rename-buffer bname)\r
+       (cond (oldbuf\r
+              (set-buffer "*info-perl-tmp*")\r
+              (rename-buffer "*info*")\r
+              (set-buffer bname)))\r
+       (make-local-variable 'window-min-height)\r
+       (setq window-min-height 2)\r
+       (current-buffer)))))\r
+\r
+(defun cperl-word-at-point (&optional p)\r
+  "Return the word at point or at P."\r
+  (save-excursion\r
+    (if p (goto-char p))\r
+    (or (cperl-word-at-point-hard)\r
+       (progn\r
+         (require 'etags)\r
+         (funcall (or (and (boundp 'find-tag-default-function)\r
+                           find-tag-default-function)\r
+                      (get major-mode 'find-tag-default-function)\r
+                      ;; XEmacs 19.12 has `find-tag-default-hook'; it is\r
+                      ;; automatically used within `find-tag-default':\r
+                      'find-tag-default))))))\r
+\r
+(defun cperl-info-on-command (command)\r
+  "Show documentation for Perl command COMMAND in other window.\r
+If perl-info buffer is shown in some frame, uses this frame.\r
+Customized by setting variables `cperl-shrink-wrap-info-frame',\r
+`cperl-max-help-size'."\r
+  (interactive\r
+   (let* ((default (cperl-word-at-point))\r
+         (read (read-string\r
+                (format "Find doc for Perl function (default %s): "\r
+                        default))))\r
+     (list (if (equal read "")\r
+              default\r
+            read))))\r
+\r
+  (let ((buffer (current-buffer))\r
+       (cmd-desc (concat "^" (regexp-quote command) "[^a-zA-Z_0-9]")) ; "tr///"\r
+       pos isvar height iniheight frheight buf win fr1 fr2 iniwin not-loner\r
+       max-height char-height buf-list)\r
+    (if (string-match "^-[a-zA-Z]$" command)\r
+       (setq cmd-desc "^-X[ \t\n]"))\r
+    (setq isvar (string-match "^[$@%]" command)\r
+         buf (cperl-info-buffer isvar)\r
+         iniwin (selected-window)\r
+         fr1 (window-frame iniwin))\r
+    (set-buffer buf)\r
+    (beginning-of-buffer)\r
+    (or isvar\r
+       (progn (re-search-forward "^-X[ \t\n]")\r
+              (forward-line -1)))\r
+    (if (re-search-forward cmd-desc nil t)\r
+       (progn\r
+         ;; Go back to beginning of the group (ex, for qq)\r
+         (if (re-search-backward "^[ \t\n\f]")\r
+             (forward-line 1))\r
+         (beginning-of-line)\r
+         ;; Get some of\r
+         (setq pos (point)\r
+               buf-list (list buf "*info-perl-var*" "*info-perl*"))\r
+         (while (and (not win) buf-list)\r
+           (setq win (get-buffer-window (car buf-list) t))\r
+           (setq buf-list (cdr buf-list)))\r
+         (or (not win)\r
+             (eq (window-buffer win) buf)\r
+             (set-window-buffer win buf))\r
+         (and win (setq fr2 (window-frame win)))\r
+         (if (or (not fr2) (eq fr1 fr2))\r
+             (pop-to-buffer buf)\r
+           (special-display-popup-frame buf) ; Make it visible\r
+           (select-window win))\r
+         (goto-char pos)               ; Needed (?!).\r
+         ;; Resize\r
+         (setq iniheight (window-height)\r
+               frheight (frame-height)\r
+               not-loner (< iniheight (1- frheight))) ; Are not alone\r
+         (cond ((if not-loner cperl-max-help-size\r
+                  cperl-shrink-wrap-info-frame)\r
+                (setq height\r
+                      (+ 2\r
+                         (count-lines\r
+                          pos\r
+                          (save-excursion\r
+                            (if (re-search-forward\r
+                                 "^[ \t][^\n]*\n+\\([^ \t\n\f]\\|\\'\\)" nil t)\r
+                                (match-beginning 0) (point-max)))))\r
+                      max-height\r
+                      (if not-loner\r
+                          (/ (* (- frheight 3) cperl-max-help-size) 100)\r
+                        (setq char-height (frame-char-height))\r
+                        ;; Non-functioning under OS/2:\r
+                        (if (eq char-height 1) (setq char-height 18))\r
+                        ;; Title, menubar, + 2 for slack\r
+                        (- (/ (x-display-pixel-height) char-height) 4)))\r
+                (if (> height max-height) (setq height max-height))\r
+                ;;(message "was %s doing %s" iniheight height)\r
+                (if not-loner\r
+                    (enlarge-window (- height iniheight))\r
+                  (set-frame-height (window-frame win) (1+ height)))))\r
+         (set-window-start (selected-window) pos))\r
+      (message "No entry for %s found." command))\r
+    ;;(pop-to-buffer buffer)\r
+    (select-window iniwin)))\r
+\r
+(defun cperl-info-on-current-command ()\r
+  "Show documentation for Perl command at point in other window."\r
+  (interactive)\r
+  (cperl-info-on-command (cperl-word-at-point)))\r
+\r
+(defun cperl-imenu-info-imenu-search ()\r
+  (if (looking-at "^-X[ \t\n]") nil\r
+    (re-search-backward\r
+     "^\n\\([-a-zA-Z_]+\\)[ \t\n]")\r
+    (forward-line 1)))\r
+\r
+(defun cperl-imenu-info-imenu-name ()\r
+  (buffer-substring\r
+   (match-beginning 1) (match-end 1)))\r
+\r
+(defun cperl-imenu-on-info ()\r
+  (interactive)\r
+  (let* ((buffer (current-buffer))\r
+        imenu-create-index-function\r
+        imenu-prev-index-position-function\r
+        imenu-extract-index-name-function\r
+        (index-item (save-restriction\r
+                      (save-window-excursion\r
+                        (set-buffer (cperl-info-buffer nil))\r
+                        (setq imenu-create-index-function\r
+                              'imenu-default-create-index-function\r
+                              imenu-prev-index-position-function\r
+                              'cperl-imenu-info-imenu-search\r
+                              imenu-extract-index-name-function\r
+                              'cperl-imenu-info-imenu-name)\r
+                        (imenu-choose-buffer-index)))))\r
+    (and index-item\r
+        (progn\r
+          (push-mark)\r
+          (pop-to-buffer "*info-perl*")\r
+          (cond\r
+           ((markerp (cdr index-item))\r
+            (goto-char (marker-position (cdr index-item))))\r
+           (t\r
+            (goto-char (cdr index-item))))\r
+          (set-window-start (selected-window) (point))\r
+          (pop-to-buffer buffer)))))\r
+\r
+(defun cperl-lineup (beg end &optional step minshift)\r
+  "Lineup construction in a region.\r
+Beginning of region should be at the start of a construction.\r
+All first occurrences of this construction in the lines that are\r
+partially contained in the region are lined up at the same column.\r
+\r
+MINSHIFT is the minimal amount of space to insert before the construction.\r
+STEP is the tabwidth to position constructions.\r
+If STEP is nil, `cperl-lineup-step' will be used\r
+\(or `cperl-indent-level', if `cperl-lineup-step' is `nil').\r
+Will not move the position at the start to the left."\r
+  (interactive "r")\r
+  (let (search col tcol seen b e)\r
+    (save-excursion\r
+      (goto-char end)\r
+      (end-of-line)\r
+      (setq end (point-marker))\r
+      (goto-char beg)\r
+      (skip-chars-forward " \t\f")\r
+      (setq beg (point-marker))\r
+      (indent-region beg end nil)\r
+      (goto-char beg)\r
+      (setq col (current-column))\r
+      (if (looking-at "[a-zA-Z0-9_]")\r
+         (if (looking-at "\\<[a-zA-Z0-9_]+\\>")\r
+             (setq search\r
+                   (concat "\\<"\r
+                           (regexp-quote\r
+                            (buffer-substring (match-beginning 0)\r
+                                              (match-end 0))) "\\>"))\r
+           (error "Cannot line up in a middle of the word"))\r
+       (if (looking-at "$")\r
+           (error "Cannot line up end of line"))\r
+       (setq search (regexp-quote (char-to-string (following-char)))))\r
+      (setq step (or step cperl-lineup-step cperl-indent-level))\r
+      (or minshift (setq minshift 1))\r
+      (while (progn\r
+              (beginning-of-line 2)\r
+              (and (< (point) end)\r
+                   (re-search-forward search end t)\r
+                   (goto-char (match-beginning 0))))\r
+       (setq tcol (current-column) seen t)\r
+       (if (> tcol col) (setq col tcol)))\r
+      (or seen\r
+         (error "The construction to line up occurred only once"))\r
+      (goto-char beg)\r
+      (setq col (+ col minshift))\r
+      (if (/= (% col step) 0) (setq step (* step (1+ (/ col step)))))\r
+      (while\r
+         (progn\r
+           (setq e (point))\r
+           (skip-chars-backward " \t")\r
+           (delete-region (point) e)\r
+           (indent-to-column col) ;(make-string (- col (current-column)) ?\ ))\r
+           (beginning-of-line 2)\r
+           (and (< (point) end)\r
+                (re-search-forward search end t)\r
+                (goto-char (match-beginning 0)))))))) ; No body\r
+\r
+(defun cperl-etags (&optional add all files)\r
+  "Run etags with appropriate options for Perl files.\r
+If optional argument ALL is `recursive', will process Perl files\r
+in subdirectories too."\r
+  (interactive)\r
+  (let ((cmd "etags")\r
+       (args '("-l" "none" "-r" "/\\<\\(package\\|sub\\)[ \\t]+\\(\\([a-zA-Z0-9:_]*::\\)?\\([a-zA-Z0-9_]+\\)[ \\t]*\\(([^()]*)[ \t]*\\)?\\([{#]\\|$\\)\\)/\\4/"))\r
+       res)\r
+    (if add (setq args (cons "-a" args)))\r
+    (or files (setq files (list buffer-file-name)))\r
+    (cond\r
+     ((eq all 'recursive)\r
+      ;;(error "Not implemented: recursive")\r
+      (setq args (append (list "-e"\r
+                              "sub wanted {push @ARGV, $File::Find::name if /\\.[pP][Llm]$/}\r
+                               use File::Find;\r
+                               find(\\&wanted, '.');\r
+                               exec @ARGV;"\r
+                              cmd) args)\r
+           cmd "perl"))\r
+     (all\r
+      ;;(error "Not implemented: all")\r
+      (setq args (append (list "-e"\r
+                              "push @ARGV, <*.PL *.pl *.pm>;\r
+                               exec @ARGV;"\r
+                              cmd) args)\r
+           cmd "perl"))\r
+     (t\r
+      (setq args (append args files))))\r
+    (setq res (apply 'call-process cmd nil nil nil args))\r
+    (or (eq res 0)\r
+       (message "etags returned \"%s\"" res))))\r
+\r
+(defun cperl-toggle-auto-newline ()\r
+  "Toggle the state of `cperl-auto-newline'."\r
+  (interactive)\r
+  (setq cperl-auto-newline (not cperl-auto-newline))\r
+  (message "Newlines will %sbe auto-inserted now."\r
+          (if cperl-auto-newline "" "not ")))\r
+\r
+(defun cperl-toggle-abbrev ()\r
+  "Toggle the state of automatic keyword expansion in CPerl mode."\r
+  (interactive)\r
+  (abbrev-mode (if abbrev-mode 0 1))\r
+  (message "Perl control structure will %sbe auto-inserted now."\r
+          (if abbrev-mode "" "not ")))\r
+\r
+\r
+(defun cperl-toggle-electric ()\r
+  "Toggle the state of parentheses doubling in CPerl mode."\r
+  (interactive)\r
+  (setq cperl-electric-parens (if (cperl-val 'cperl-electric-parens) 'null t))\r
+  (message "Parentheses will %sbe auto-doubled now."\r
+          (if (cperl-val 'cperl-electric-parens) "" "not ")))\r
+\r
+(defun cperl-toggle-autohelp ()\r
+  "Toggle the state of Auto-Help on Perl constructs (put in the message area).\r
+Delay of auto-help controlled by `cperl-lazy-help-time'."\r
+  (interactive)\r
+  (if (fboundp 'run-with-idle-timer)\r
+      (progn\r
+       (if cperl-lazy-installed\r
+           (cperl-lazy-unstall)\r
+         (cperl-lazy-install))\r
+       (message "Perl help messages will %sbe automatically shown now."\r
+                (if cperl-lazy-installed "" "not ")))\r
+    (message "Cannot automatically show Perl help messages - run-with-idle-timer missing.")))\r
+\r
+(defun cperl-toggle-construct-fix ()\r
+  "Toggle whether `indent-region'/`indent-sexp' fix whitespace too."\r
+  (interactive)\r
+  (setq cperl-indent-region-fix-constructs\r
+       (if cperl-indent-region-fix-constructs\r
+           nil\r
+         1))\r
+  (message "indent-region/indent-sexp will %sbe automatically fix whitespace."\r
+          (if cperl-indent-region-fix-constructs "" "not ")))\r
+\r
+;;;; Tags file creation.\r
+\r
+(defvar cperl-tmp-buffer " *cperl-tmp*")\r
+\r
+(defun cperl-setup-tmp-buf ()\r
+  (set-buffer (get-buffer-create cperl-tmp-buffer))\r
+  (set-syntax-table cperl-mode-syntax-table)\r
+  (buffer-disable-undo)\r
+  (auto-fill-mode 0)\r
+  (if cperl-use-syntax-table-text-property-for-tags\r
+      (progn\r
+       (make-local-variable 'parse-sexp-lookup-properties)\r
+       ;; Do not introduce variable if not needed, we check it!\r
+       (set 'parse-sexp-lookup-properties t))))\r
+\r
+(defun cperl-xsub-scan ()\r
+  (require 'cl)\r
+  (require 'imenu)\r
+  (let ((index-alist '())\r
+       (prev-pos 0) index index1 name package prefix)\r
+    (goto-char (point-min))\r
+    (if noninteractive\r
+       (message "Scanning XSUB for index")\r
+      (imenu-progress-message prev-pos 0))\r
+    ;; Search for the function\r
+    (progn ;;save-match-data\r
+      (while (re-search-forward\r
+             "^\\([ \t]*MODULE\\>[^\n]*\\<PACKAGE[ \t]*=[ \t]*\\([a-zA-Z_][a-zA-Z_0-9:]*\\)\\>\\|\\([a-zA-Z_][a-zA-Z_0-9]*\\)(\\|[ \t]*BOOT:\\)"\r
+             nil t)\r
+       (or noninteractive\r
+           (imenu-progress-message prev-pos))\r
+       (cond\r
+        ((match-beginning 2)           ; SECTION\r
+         (setq package (buffer-substring (match-beginning 2) (match-end 2)))\r
+         (goto-char (match-beginning 0))\r
+         (skip-chars-forward " \t")\r
+         (forward-char 1)\r
+         (if (looking-at "[^\n]*\\<PREFIX[ \t]*=[ \t]*\\([a-zA-Z_][a-zA-Z_0-9]*\\)\\>")\r
+             (setq prefix (buffer-substring (match-beginning 1) (match-end 1)))\r
+           (setq prefix nil)))\r
+        ((not package) nil)            ; C language section\r
+        ((match-beginning 3)           ; XSUB\r
+         (goto-char (1+ (match-beginning 3)))\r
+         (setq index (imenu-example--name-and-position))\r
+         (setq name (buffer-substring (match-beginning 3) (match-end 3)))\r
+         (if (and prefix (string-match (concat "^" prefix) name))\r
+             (setq name (substring name (length prefix))))\r
+         (cond ((string-match "::" name) nil)\r
+               (t\r
+                (setq index1 (cons (concat package "::" name) (cdr index)))\r
+                (push index1 index-alist)))\r
+         (setcar index name)\r
+         (push index index-alist))\r
+        (t                             ; BOOT: section\r
+         ;; (beginning-of-line)\r
+         (setq index (imenu-example--name-and-position))\r
+         (setcar index (concat package "::BOOT:"))\r
+         (push index index-alist)))))\r
+    (or noninteractive\r
+       (imenu-progress-message prev-pos 100))\r
+    index-alist))\r
+\r
+(defvar cperl-unreadable-ok nil)\r
+\r
+(defun cperl-find-tags (ifile xs topdir)\r
+  (let ((b (get-buffer cperl-tmp-buffer)) ind lst elt pos ret rel\r
+       (cperl-pod-here-fontify nil) f file)\r
+    (save-excursion\r
+      (if b (set-buffer b)\r
+       (cperl-setup-tmp-buf))\r
+      (erase-buffer)\r
+      (condition-case err\r
+         (setq file (car (insert-file-contents ifile)))\r
+       (error (if cperl-unreadable-ok nil\r
+                (if (y-or-n-p\r
+                     (format "File %s unreadable.  Continue? " ifile))\r
+                    (setq cperl-unreadable-ok t)\r
+                  (error "Aborting: unreadable file %s" ifile)))))\r
+      (if (not file)\r
+         (message "Unreadable file %s" ifile)\r
+       (message "Scanning file %s ..." file)\r
+       (if (and cperl-use-syntax-table-text-property-for-tags\r
+                (not xs))\r
+           (condition-case err         ; after __END__ may have garbage\r
+               (cperl-find-pods-heres nil nil noninteractive)\r
+             (error (message "While scanning for syntax: %s" err))))\r
+       (if xs\r
+           (setq lst (cperl-xsub-scan))\r
+         (setq ind (cperl-imenu--create-perl-index))\r
+         (setq lst (cdr (assoc "+Unsorted List+..." ind))))\r
+       (setq lst\r
+             (mapcar\r
+              (function\r
+               (lambda (elt)\r
+                 (cond ((string-match "^[_a-zA-Z]" (car elt))\r
+                        (goto-char (cdr elt))\r
+                        (beginning-of-line) ; pos should be of the start of the line\r
+                        (list (car elt)\r
+                              (point)\r
+                              (1+ (count-lines 1 (point))) ; 1+ since at beg-o-l\r
+                              (buffer-substring (progn\r
+                                                  (goto-char (cdr elt))\r
+                                                  ;; After name now...\r
+                                                  (or (eolp) (forward-char 1))\r
+                                                  (point))\r
+                                                (progn\r
+                                                  (beginning-of-line)\r
+                                                  (point))))))))\r
+              lst))\r
+       (erase-buffer)\r
+       (while lst\r
+         (setq elt (car lst) lst (cdr lst))\r
+         (if elt\r
+             (progn\r
+               (insert (elt elt 3)\r
+                       127\r
+                       (if (string-match "^package " (car elt))\r
+                           (substring (car elt) 8)\r
+                         (car elt) )\r
+                       1\r
+                       (number-to-string (elt elt 2)) ; Line\r
+                       ","\r
+                       (number-to-string (1- (elt elt 1))) ; Char pos 0-based\r
+                       "\n")\r
+               (if (and (string-match "^[_a-zA-Z]+::" (car elt))\r
+                        (string-match "^sub[ \t]+\\([_a-zA-Z]+\\)[^:_a-zA-Z]"\r
+                                      (elt elt 3)))\r
+                   ;; Need to insert the name without package as well\r
+                   (setq lst (cons (cons (substring (elt elt 3) \r
+                                                    (match-beginning 1)\r
+                                                    (match-end 1))\r
+                                         (cdr elt))\r
+                                   lst))))))\r
+       (setq pos (point))\r
+       (goto-char 1)\r
+       (setq rel file)\r
+       ;; On case-preserving filesystems (EMX on OS/2) case might be encoded in properties\r
+       (set-text-properties 0 (length rel) nil rel)\r
+       (and (equal topdir (substring rel 0 (length topdir)))\r
+            (setq rel (substring file (length topdir))))\r
+       (insert "\f\n" rel "," (number-to-string (1- pos)) "\n")\r
+       (setq ret (buffer-substring 1 (point-max)))\r
+       (erase-buffer)\r
+       (or noninteractive\r
+           (message "Scanning file %s finished" file))\r
+       ret))))\r
+\r
+(defun cperl-add-tags-recurse-noxs ()\r
+  "Add to TAGS data for Perl and XSUB files in the current directory and kids.\r
+Use as\r
+  emacs -batch -q -no-site-file -l emacs/cperl-mode.el \\r
+        -f cperl-add-tags-recurse\r
+"\r
+  (cperl-write-tags nil nil t t nil t))\r
+\r
+(defun cperl-add-tags-recurse ()\r
+  "Add to TAGS file data for Perl files in the current directory and kids.\r
+Use as\r
+  emacs -batch -q -no-site-file -l emacs/cperl-mode.el \\r
+        -f cperl-add-tags-recurse\r
+"\r
+  (cperl-write-tags nil nil t t))\r
+\r
+(defun cperl-write-tags (&optional file erase recurse dir inbuffer noxs topdir)\r
+  ;; If INBUFFER, do not select buffer, and do not save\r
+  ;; If ERASE is `ignore', do not erase, and do not try to delete old info.\r
+  (require 'etags)\r
+  (if file nil\r
+    (setq file (if dir default-directory (buffer-file-name)))\r
+    (if (and (not dir) (buffer-modified-p)) (error "Save buffer first!")))\r
+  (or topdir\r
+      (setq topdir default-directory))\r
+  (let ((tags-file-name "TAGS")\r
+       (case-fold-search (eq system-type 'emx))\r
+       xs rel tm)\r
+    (save-excursion\r
+      (cond (inbuffer nil)             ; Already there\r
+           ((file-exists-p tags-file-name)\r
+            (if cperl-xemacs-p\r
+                (visit-tags-table-buffer)\r
+              (visit-tags-table-buffer tags-file-name)))\r
+           (t (set-buffer (find-file-noselect tags-file-name))))\r
+      (cond\r
+       (dir\r
+       (cond ((eq erase 'ignore))\r
+             (erase\r
+              (erase-buffer)\r
+              (setq erase 'ignore)))\r
+       (let ((files\r
+              (condition-case err\r
+                  (directory-files file t\r
+                                   (if recurse nil cperl-scan-files-regexp)\r
+                                   t)\r
+                (error\r
+                 (if cperl-unreadable-ok nil\r
+                   (if (y-or-n-p\r
+                        (format "Directory %s unreadable.  Continue? " file))\r
+                       (setq cperl-unreadable-ok t\r
+                             tm nil)   ; Return empty list\r
+                     (error "Aborting: unreadable directory %s" file)))))))\r
+         (mapcar (function \r
+                  (lambda (file)\r
+                    (cond\r
+                     ((string-match cperl-noscan-files-regexp file)\r
+                      nil)\r
+                     ((not (file-directory-p file))\r
+                      (if (string-match cperl-scan-files-regexp file)\r
+                          (cperl-write-tags file erase recurse nil t noxs topdir)))\r
+                     ((not recurse) nil)\r
+                     (t (cperl-write-tags file erase recurse t t noxs topdir)))))\r
+                 files)))\r
+       (t\r
+       (setq xs (string-match "\\.xs$" file))\r
+       (if (not (and xs noxs))\r
+           (progn\r
+             (cond ((eq erase 'ignore) (goto-char (point-max)))\r
+                   (erase (erase-buffer))\r
+                   (t\r
+                    (goto-char 1)\r
+                    (setq rel file)\r
+                    ;; On case-preserving filesystems (EMX on OS/2) case might be encoded in properties\r
+                    (set-text-properties 0 (length rel) nil rel)\r
+                    (and (equal topdir (substring rel 0 (length topdir)))\r
+                         (setq rel (substring file (length topdir))))\r
+                    (if (search-forward (concat "\f\n" rel ",") nil t)\r
+                        (progn\r
+                          (search-backward "\f\n")\r
+                          (delete-region (point)\r
+                                         (save-excursion\r
+                                           (forward-char 1)\r
+                                           (if (search-forward "\f\n"\r
+                                                               nil 'toend)\r
+                                               (- (point) 2)\r
+                                             (point-max)))))\r
+                      (goto-char (point-max)))))\r
+             (insert (cperl-find-tags file xs topdir))))))\r
+      (if inbuffer nil                 ; Delegate to the caller\r
+       (save-buffer 0)                 ; No backup\r
+       (if (fboundp 'initialize-new-tags-table) ; Do we need something special in XEmacs?\r
+           (initialize-new-tags-table))))))\r
+\r
+(defvar cperl-tags-hier-regexp-list\r
+  (concat\r
+   "^\\("\r
+      "\\(package\\)\\>"\r
+     "\\|"\r
+      "sub\\>[^\n]+::"\r
+     "\\|"\r
+      "[a-zA-Z_][a-zA-Z_0-9:]*(\C-?[^\n]+::" ; XSUB?\r
+     "\\|"\r
+      "[ \t]*BOOT:\C-?[^\n]+::"                ; BOOT section\r
+   "\\)"))\r
+\r
+(defvar cperl-hierarchy '(() ())\r
+  "Global hierarchy of classes.")\r
+\r
+(defun cperl-tags-hier-fill ()\r
+  ;; Suppose we are in a tag table cooked by cperl.\r
+  (goto-char 1)\r
+  (let (type pack name pos line chunk ord cons1 file str info fileind)\r
+    (while (re-search-forward cperl-tags-hier-regexp-list nil t)\r
+      (setq pos (match-beginning 0)\r
+           pack (match-beginning 2))\r
+      (beginning-of-line)\r
+      (if (looking-at (concat\r
+                      "\\([^\n]+\\)"\r
+                      "\C-?"\r
+                      "\\([^\n]+\\)"\r
+                      "\C-a"\r
+                      "\\([0-9]+\\)"\r
+                      ","\r
+                      "\\([0-9]+\\)"))\r
+         (progn\r
+           (setq ;;str (buffer-substring (match-beginning 1) (match-end 1))\r
+                 name (buffer-substring (match-beginning 2) (match-end 2))\r
+                 ;;pos (buffer-substring (match-beginning 3) (match-end 3))\r
+                 line (buffer-substring (match-beginning 3) (match-end 3))\r
+                 ord (if pack 1 0)\r
+                 file (file-of-tag)\r
+                 fileind (format "%s:%s" file line)\r
+                 ;; Moves to beginning of the next line:\r
+                 info (cperl-etags-snarf-tag file line))\r
+           ;; Move back\r
+           (forward-char -1)\r
+           ;; Make new member of hierarchy name ==> file ==> pos if needed\r
+           (if (setq cons1 (assoc name (nth ord cperl-hierarchy)))\r
+               ;; Name known\r
+               (setcdr cons1 (cons (cons fileind (vector file info))\r
+                                   (cdr cons1)))\r
+             ;; First occurrence of the name, start alist\r
+             (setq cons1 (cons name (list (cons fileind (vector file info)))))\r
+             (if pack\r
+                 (setcar (cdr cperl-hierarchy)\r
+                         (cons cons1 (nth 1 cperl-hierarchy)))\r
+               (setcar cperl-hierarchy\r
+                       (cons cons1 (car cperl-hierarchy)))))))\r
+      (end-of-line))))\r
+\r
+(defun cperl-tags-hier-init (&optional update)\r
+  "Show hierarchical menu of classes and methods.\r
+Finds info about classes by a scan of loaded TAGS files.\r
+Supposes that the TAGS files contain fully qualified function names.\r
+One may build such TAGS files from CPerl mode menu."\r
+  (interactive)\r
+  (require 'etags)\r
+  (require 'imenu)\r
+  (if (or update (null (nth 2 cperl-hierarchy)))\r
+      (let ((remover (function (lambda (elt) ; (name (file1...) (file2..))\r
+                                (or (nthcdr 2 elt)\r
+                                    ;; Only in one file\r
+                                    (setcdr elt (cdr (nth 1 elt)))))))\r
+           pack name cons1 to l1 l2 l3 l4 b)\r
+       ;; (setq cperl-hierarchy '(() () ())) ; Would write into '() later!\r
+       (setq cperl-hierarchy (list l1 l2 l3))\r
+       (if cperl-xemacs-p              ; Not checked\r
+           (progn\r
+             (or tags-file-name\r
+                 ;; Does this work in XEmacs?\r
+                 (call-interactively 'visit-tags-table))\r
+             (message "Updating list of classes...")\r
+             (set-buffer (get-file-buffer tags-file-name))\r
+             (cperl-tags-hier-fill))\r
+         (or tags-table-list\r
+             (call-interactively 'visit-tags-table))\r
+         (mapcar \r
+          (function\r
+           (lambda (tagsfile)\r
+             (message "Updating list of classes... %s" tagsfile)\r
+             (set-buffer (get-file-buffer tagsfile))\r
+             (cperl-tags-hier-fill)))\r
+          tags-table-list)\r
+         (message "Updating list of classes... postprocessing..."))\r
+       (mapcar remover (car cperl-hierarchy))\r
+       (mapcar remover (nth 1 cperl-hierarchy))\r
+       (setq to (list nil (cons "Packages: " (nth 1 cperl-hierarchy))\r
+                      (cons "Methods: " (car cperl-hierarchy))))\r
+       (cperl-tags-treeify to 1)\r
+       (setcar (nthcdr 2 cperl-hierarchy)\r
+               (cperl-menu-to-keymap (cons '("+++UPDATE+++" . -999) (cdr to))))\r
+       (message "Updating list of classes: done, requesting display...")\r
+       ;;(cperl-imenu-addback (nth 2 cperl-hierarchy))\r
+       ))\r
+  (or (nth 2 cperl-hierarchy)\r
+      (error "No items found"))\r
+  (setq update\r
+;;;    (imenu-choose-buffer-index "Packages: " (nth 2 cperl-hierarchy))\r
+       (if (if (boundp 'display-popup-menus-p)\r
+               (let ((f 'display-popup-menus-p))\r
+                 (funcall f))\r
+             window-system)\r
+           (x-popup-menu t (nth 2 cperl-hierarchy))\r
+         (require 'tmm)\r
+         (tmm-prompt (nth 2 cperl-hierarchy))))\r
+  (if (and update (listp update))\r
+      (progn (while (cdr update) (setq update (cdr update)))\r
+            (setq update (car update)))) ; Get the last from the list\r
+  (if (vectorp update)\r
+      (progn\r
+       (find-file (elt update 0))\r
+       (cperl-etags-goto-tag-location (elt update 1))))\r
+  (if (eq update -999) (cperl-tags-hier-init t)))\r
+\r
+(defun cperl-tags-treeify (to level)\r
+  ;; cadr of `to' is read-write.  On start it is a cons\r
+  (let* ((regexp (concat "^\\(" (mapconcat\r
+                                'identity\r
+                                (make-list level "[_a-zA-Z0-9]+")\r
+                                "::")\r
+                        "\\)\\(::\\)?"))\r
+        (packages (cdr (nth 1 to)))\r
+        (methods (cdr (nth 2 to)))\r
+        l1 head tail cons1 cons2 ord writeto packs recurse\r
+        root-packages root-functions ms many_ms same_name ps\r
+        (move-deeper\r
+         (function \r
+          (lambda (elt)\r
+            (cond ((and (string-match regexp (car elt))\r
+                        (or (eq ord 1) (match-end 2)))\r
+                   (setq head (substring (car elt) 0 (match-end 1))\r
+                         tail (if (match-end 2) (substring (car elt) \r
+                                                           (match-end 2)))\r
+                         recurse t)\r
+                   (if (setq cons1 (assoc head writeto)) nil\r
+                     ;; Need to init new head\r
+                     (setcdr writeto (cons (list head (list "Packages: ")\r
+                                                 (list "Methods: "))\r
+                                           (cdr writeto)))\r
+                     (setq cons1 (nth 1 writeto)))\r
+                   (setq cons2 (nth ord cons1)) ; Either packs or meths\r
+                   (setcdr cons2 (cons elt (cdr cons2))))\r
+                  ((eq ord 2)\r
+                   (setq root-functions (cons elt root-functions)))\r
+                  (t\r
+                   (setq root-packages (cons elt root-packages))))))))\r
+    (setcdr to l1)                     ; Init to dynamic space\r
+    (setq writeto to)\r
+    (setq ord 1)\r
+    (mapcar move-deeper packages)\r
+    (setq ord 2)\r
+    (mapcar move-deeper methods)\r
+    (if recurse\r
+       (mapcar (function (lambda (elt)\r
+                         (cperl-tags-treeify elt (1+ level))))\r
+               (cdr to)))\r
+    ;;Now clean up leaders with one child only\r
+    (mapcar (function (lambda (elt)\r
+                       (if (not (and (listp (cdr elt)) \r
+                                     (eq (length elt) 2))) nil\r
+                           (setcar elt (car (nth 1 elt)))\r
+                           (setcdr elt (cdr (nth 1 elt))))))\r
+           (cdr to))\r
+    ;; Sort the roots of subtrees\r
+    (if (default-value 'imenu-sort-function)\r
+       (setcdr to\r
+               (sort (cdr to) (default-value 'imenu-sort-function))))\r
+    ;; Now add back functions removed from display\r
+    (mapcar (function (lambda (elt)\r
+                       (setcdr to (cons elt (cdr to)))))\r
+           (if (default-value 'imenu-sort-function)\r
+               (nreverse\r
+                (sort root-functions (default-value 'imenu-sort-function)))\r
+             root-functions))\r
+    ;; Now add back packages removed from display\r
+    (mapcar (function (lambda (elt)\r
+                       (setcdr to (cons (cons (concat "package " (car elt)) \r
+                                              (cdr elt)) \r
+                                        (cdr to)))))\r
+           (if (default-value 'imenu-sort-function)\r
+               (nreverse\r
+                (sort root-packages (default-value 'imenu-sort-function)))\r
+             root-packages))))\r
+\r
+;;;(x-popup-menu t\r
+;;;   '(keymap "Name1"\r
+;;;        ("Ret1" "aa")\r
+;;;        ("Head1" "ab"\r
+;;;         keymap "Name2"\r
+;;;         ("Tail1" "x") ("Tail2" "y"))))\r
+\r
+(defun cperl-list-fold (list name limit)\r
+  (let (list1 list2 elt1 (num 0))\r
+    (if (<= (length list) limit) list\r
+      (setq list1 nil list2 nil)\r
+      (while list\r
+       (setq num (1+ num)\r
+             elt1 (car list)\r
+             list (cdr list))\r
+       (if (<= num imenu-max-items)\r
+           (setq list2 (cons elt1 list2))\r
+         (setq list1 (cons (cons name\r
+                                 (nreverse list2))\r
+                           list1)\r
+               list2 (list elt1)\r
+               num 1)))\r
+      (nreverse (cons (cons name\r
+                           (nreverse list2))\r
+                     list1)))))\r
+\r
+(defun cperl-menu-to-keymap (menu &optional name)\r
+  (let (list)\r
+    (cons 'keymap\r
+         (mapcar\r
+          (function\r
+           (lambda (elt)\r
+             (cond ((listp (cdr elt))\r
+                    (setq list (cperl-list-fold\r
+                                (cdr elt) (car elt) imenu-max-items))\r
+                    (cons nil\r
+                          (cons (car elt)\r
+                                (cperl-menu-to-keymap list))))\r
+                   (t\r
+                    (list (cdr elt) (car elt) t))))) ; t is needed in 19.34\r
+          (cperl-list-fold menu "Root" imenu-max-items)))))\r
+\r
+\f\r
+(defvar cperl-bad-style-regexp\r
+  (mapconcat 'identity\r
+            '("[^-\n\t <>=+!.&|(*/'`\"#^][-=+<>!|&^]" ; char sign\r
+              "[-<>=+^&|]+[^- \t\n=+<>~]") ; sign+ char \r
+            "\\|")\r
+  "Finds places such that insertion of a whitespace may help a lot.")\r
+\r
+(defvar cperl-not-bad-style-regexp\r
+  (mapconcat \r
+   'identity\r
+   '("[^-\t <>=+]\\(--\\|\\+\\+\\)"    ; var-- var++\r
+     "[a-zA-Z0-9_][|&][a-zA-Z0-9_$]"   ; abc|def abc&def are often used.\r
+     "&[(a-zA-Z0-9_$]"                 ; &subroutine &(var->field)\r
+     "<\\$?\\sw+\\(\\.\\sw+\\)?>"      ; <IN> <stdin.h>\r
+     "-[a-zA-Z][ \t]+[_$\"'`a-zA-Z]"   ; -f file, -t STDIN\r
+     "-[0-9]"                          ; -5\r
+     "\\+\\+"                          ; ++var\r
+     "--"                              ; --var\r
+     ".->"                             ; a->b\r
+     "->"                              ; a SPACE ->b\r
+     "\\[-"                            ; a[-1]\r
+     "\\\\[&$@*\\\\]"                  ; \&func\r
+     "^="                              ; =head\r
+     "\\$."                            ; $|\r
+     "<<[a-zA-Z_'\"`]"                 ; <<FOO, <<'FOO'\r
+     "||"\r
+     "&&"\r
+     "[CBIXSLFZ]<\\(\\sw\\|\\s \\|\\s_\\|[\n]\\)*>" ; C<code like text>\r
+     "-[a-zA-Z_0-9]+[ \t]*=>"          ; -option => value\r
+     ;; Unaddressed trouble spots: = -abc, f(56, -abc) --- specialcased below\r
+     ;;"[*/+-|&<.]+="\r
+     )\r
+   "\\|")\r
+  "If matches at the start of match found by `my-bad-c-style-regexp',\r
+insertion of a whitespace will not help.")\r
+\r
+(defvar found-bad)\r
+\r
+(defun cperl-find-bad-style ()\r
+  "Find places in the buffer where insertion of a whitespace may help.\r
+Prompts user for insertion of spaces.\r
+Currently it is tuned to C and Perl syntax."\r
+  (interactive)\r
+  (let (found-bad (p (point)))\r
+    (setq last-nonmenu-event 13)       ; To disable popup\r
+    (beginning-of-buffer)\r
+    (map-y-or-n-p "Insert space here? "\r
+                 (lambda (arg) (insert " "))\r
+                 'cperl-next-bad-style\r
+                 '("location" "locations" "insert a space into")\r
+                 '((?\C-r (lambda (arg)\r
+                            (let ((buffer-quit-function\r
+                                   'exit-recursive-edit))\r
+                              (message "Exit with Esc Esc")\r
+                              (recursive-edit)\r
+                              t))      ; Consider acted upon\r
+                          "edit, exit with Esc Esc")\r
+                   (?e (lambda (arg)\r
+                         (let ((buffer-quit-function\r
+                                'exit-recursive-edit))\r
+                           (message "Exit with Esc Esc")\r
+                           (recursive-edit)\r
+                           t))         ; Consider acted upon\r
+                       "edit, exit with Esc Esc"))\r
+                 t)\r
+    (if found-bad (goto-char found-bad)\r
+      (goto-char p)\r
+      (message "No appropriate place found"))))\r
+\r
+(defun cperl-next-bad-style ()\r
+  (let (p (not-found t) (point (point)) found)\r
+    (while (and not-found\r
+               (re-search-forward cperl-bad-style-regexp nil 'to-end))\r
+      (setq p (point))\r
+      (goto-char (match-beginning 0))\r
+      (if (or\r
+          (looking-at cperl-not-bad-style-regexp)\r
+          ;; Check for a < -b and friends\r
+          (and (eq (following-char) ?\-)\r
+               (save-excursion\r
+                 (skip-chars-backward " \t\n")\r
+                 (memq (preceding-char) '(?\= ?\> ?\< ?\, ?\( ?\[ ?\{))))\r
+          ;; Now check for syntax type\r
+          (save-match-data\r
+            (setq found (point))\r
+            (beginning-of-defun)\r
+            (let ((pps (parse-partial-sexp (point) found)))\r
+              (or (nth 3 pps) (nth 4 pps) (nth 5 pps)))))\r
+         (goto-char (match-end 0))\r
+       (goto-char (1- p))\r
+       (setq not-found nil\r
+             found-bad found)))\r
+    (not not-found)))\r
+\r
+\f\r
+;;; Getting help\r
+(defvar cperl-have-help-regexp\r
+  ;;(concat "\\("\r
+  (mapconcat\r
+   'identity\r
+   '("[$@%*&][0-9a-zA-Z_:]+\\([ \t]*[[{]\\)?" ; Usual variable\r
+     "[$@]\\^[a-zA-Z]"                 ; Special variable\r
+     "[$@][^ \n\t]"                    ; Special variable\r
+     "-[a-zA-Z]"                       ; File test\r
+     "\\\\[a-zA-Z0]"                   ; Special chars\r
+     "^=[a-z][a-zA-Z0-9_]*"            ; POD sections\r
+     "[-!&*+,-./<=>?\\\\^|~]+"         ; Operator\r
+     "[a-zA-Z_0-9:]+"                  ; symbol or number\r
+     "x="\r
+     "#!")\r
+   ;;"\\)\\|\\("\r
+   "\\|")\r
+  ;;"\\)"\r
+  ;;)\r
+  "Matches places in the buffer we can find help for.")\r
+\r
+(defvar cperl-message-on-help-error t)\r
+(defvar cperl-help-from-timer nil)\r
+\r
+(defun cperl-word-at-point-hard ()\r
+  ;; Does not save-excursion\r
+  ;; Get to the something meaningful\r
+  (or (eobp) (eolp) (forward-char 1))\r
+  (re-search-backward "[-a-zA-Z0-9_:!&*+,-./<=>?\\\\^|~$%@]"\r
+                     (save-excursion (beginning-of-line) (point))\r
+                     'to-beg)\r
+  ;;  (cond\r
+  ;;   ((or (eobp) (looking-at "[][ \t\n{}();,]")) ; Not at a symbol\r
+  ;;    (skip-chars-backward " \n\t\r({[]});,")\r
+  ;;    (or (bobp) (backward-char 1))))\r
+  ;; Try to backtrace\r
+  (cond\r
+   ((looking-at "[a-zA-Z0-9_:]")       ; symbol\r
+    (skip-chars-backward "a-zA-Z0-9_:")\r
+    (cond\r
+     ((and (eq (preceding-char) ?^)    ; $^I\r
+          (eq (char-after (- (point) 2)) ?\$))\r
+      (forward-char -2))\r
+     ((memq (preceding-char) (append "*$@%&\\" nil)) ; *glob\r
+      (forward-char -1))\r
+     ((and (eq (preceding-char) ?\=)\r
+          (eq (current-column) 1))\r
+      (forward-char -1)))              ; =head1\r
+    (if (and (eq (preceding-char) ?\<)\r
+            (looking-at "\\$?[a-zA-Z0-9_:]+>")) ; <FH>\r
+       (forward-char -1)))\r
+   ((and (looking-at "=") (eq (preceding-char) ?x)) ; x=\r
+    (forward-char -1))\r
+   ((and (looking-at "\\^") (eq (preceding-char) ?\$)) ; $^I\r
+    (forward-char -1))\r
+   ((looking-at "[-!&*+,-./<=>?\\\\^|~]")\r
+    (skip-chars-backward "-!&*+,-./<=>?\\\\^|~")\r
+    (cond\r
+     ((and (eq (preceding-char) ?\$)\r
+          (not (eq (char-after (- (point) 2)) ?\$))) ; $-\r
+      (forward-char -1))\r
+     ((and (eq (following-char) ?\>)\r
+          (string-match "[a-zA-Z0-9_]" (char-to-string (preceding-char)))\r
+          (save-excursion\r
+            (forward-sexp -1)\r
+            (and (eq (preceding-char) ?\<)\r
+                 (looking-at "\\$?[a-zA-Z0-9_:]+>")))) ; <FH>\r
+      (search-backward "<"))))\r
+   ((and (eq (following-char) ?\$)\r
+        (eq (preceding-char) ?\<)\r
+        (looking-at "\\$?[a-zA-Z0-9_:]+>")) ; <$fh>\r
+    (forward-char -1)))\r
+  (if (looking-at cperl-have-help-regexp)\r
+      (buffer-substring (match-beginning 0) (match-end 0))))\r
+\r
+(defun cperl-get-help ()\r
+  "Get one-line docs on the symbol at the point.\r
+The data for these docs is a little bit obsolete and may be in fact longer\r
+than a line.  Your contribution to update/shorten it is appreciated."\r
+  (interactive)\r
+  (save-match-data                     ; May be called "inside" query-replace\r
+    (save-excursion\r
+      (let ((word (cperl-word-at-point-hard)))\r
+       (if word\r
+           (if (and cperl-help-from-timer ; Bail out if not in mainland\r
+                    (not (string-match "^#!\\|\\\\\\|^=" word)) ; Show help even in comments/strings.\r
+                    (or (memq (get-text-property (point) 'face)\r
+                              '(font-lock-comment-face font-lock-string-face))\r
+                        (memq (get-text-property (point) 'syntax-type)\r
+                              '(pod here-doc format))))\r
+               nil\r
+             (cperl-describe-perl-symbol word))\r
+         (if cperl-message-on-help-error\r
+             (message "Nothing found for %s..."\r
+                      (buffer-substring (point) (min (+ 5 (point)) (point-max))))))))))\r
+\r
+;;; Stolen from perl-descr.el by Johan Vromans:\r
+\r
+(defvar cperl-doc-buffer " *perl-doc*"\r
+  "Where the documentation can be found.")\r
+\r
+(defun cperl-describe-perl-symbol (val)\r
+  "Display the documentation of symbol at point, a Perl operator."\r
+  (let ((enable-recursive-minibuffers t)\r
+       args-file regexp)\r
+    (cond\r
+     ((string-match "^[&*][a-zA-Z_]" val)\r
+      (setq val (concat (substring val 0 1) "NAME")))\r
+     ((string-match "^[$@]\\([a-zA-Z_:0-9]+\\)[ \t]*\\[" val)\r
+      (setq val (concat "@" (substring val 1 (match-end 1)))))\r
+     ((string-match "^[$@]\\([a-zA-Z_:0-9]+\\)[ \t]*{" val)\r
+      (setq val (concat "%" (substring val 1 (match-end 1)))))\r
+     ((and (string= val "x") (string-match "^x=" val))\r
+      (setq val "x="))\r
+     ((string-match "^\\$[\C-a-\C-z]" val)\r
+      (setq val (concat "$^" (char-to-string (+ ?A -1 (aref val 1))))))\r
+     ((string-match "^CORE::" val)\r
+      (setq val "CORE::"))\r
+     ((string-match "^SUPER::" val)\r
+      (setq val "SUPER::"))\r
+     ((and (string= "<" val) (string-match "^<\\$?[a-zA-Z0-9_:]+>" val))\r
+      (setq val "<NAME>")))\r
+    (setq regexp (concat "^"\r
+                        "\\([^a-zA-Z0-9_:]+[ \t]+\\)?"\r
+                        (regexp-quote val)\r
+                        "\\([ \t([/]\\|$\\)"))\r
+\r
+    ;; get the buffer with the documentation text\r
+    (cperl-switch-to-doc-buffer)\r
+\r
+    ;; lookup in the doc\r
+    (goto-char (point-min))\r
+    (let ((case-fold-search nil))\r
+      (list\r
+       (if (re-search-forward regexp (point-max) t)\r
+          (save-excursion\r
+            (beginning-of-line 1)\r
+            (let ((lnstart (point)))\r
+              (end-of-line)\r
+              (message "%s" (buffer-substring lnstart (point)))))\r
+        (if cperl-message-on-help-error\r
+            (message "No definition for %s" val)))))))\r
+\r
+(defvar cperl-short-docs 'please-ignore-this-line\r
+  ;; Perl4 version was written by Johan Vromans (jvromans@squirrel.nl)\r
+  "# based on '@(#)@ perl-descr.el 1.9 - describe-perl-symbol' [Perl 5]\r
+...    Range (list context); flip/flop [no flop when flip] (scalar context).\r
+! ...  Logical negation.\r
+... != ...     Numeric inequality.\r
+... !~ ...     Search pattern, substitution, or translation (negated).\r
+$!     In numeric context: errno.  In a string context: error string.\r
+$\"    The separator which joins elements of arrays interpolated in strings.\r
+$#     The output format for printed numbers.  Default is %.15g or close.\r
+$$     Process number of this script.  Changes in the fork()ed child process.\r
+$%     The current page number of the currently selected output channel.\r
+\r
+       The following variables are always local to the current block:\r
+\r
+$1     Match of the 1st set of parentheses in the last match (auto-local).\r
+$2     Match of the 2nd set of parentheses in the last match (auto-local).\r
+$3     Match of the 3rd set of parentheses in the last match (auto-local).\r
+$4     Match of the 4th set of parentheses in the last match (auto-local).\r
+$5     Match of the 5th set of parentheses in the last match (auto-local).\r
+$6     Match of the 6th set of parentheses in the last match (auto-local).\r
+$7     Match of the 7th set of parentheses in the last match (auto-local).\r
+$8     Match of the 8th set of parentheses in the last match (auto-local).\r
+$9     Match of the 9th set of parentheses in the last match (auto-local).\r
+$&     The string matched by the last pattern match (auto-local).\r
+$'     The string after what was matched by the last match (auto-local).\r
+$`     The string before what was matched by the last match (auto-local).\r
+\r
+$(     The real gid of this process.\r
+$)     The effective gid of this process.\r
+$*     Deprecated: Set to 1 to do multiline matching within a string.\r
+$+     The last bracket matched by the last search pattern.\r
+$,     The output field separator for the print operator.\r
+$-     The number of lines left on the page.\r
+$.     The current input line number of the last filehandle that was read.\r
+$/     The input record separator, newline by default.\r
+$0     Name of the file containing the current perl script (read/write).\r
+$:     String may be broken after these characters to fill ^-lines in a format.\r
+$;     Subscript separator for multi-dim array emulation.  Default \"\\034\".\r
+$<     The real uid of this process.\r
+$=     The page length of the current output channel.  Default is 60 lines.\r
+$>     The effective uid of this process.\r
+$?     The status returned by the last ``, pipe close or `system'.\r
+$@     The perl error message from the last eval or do @var{EXPR} command.\r
+$ARGV  The name of the current file used with <> .\r
+$[     Deprecated: The index of the first element/char in an array/string.\r
+$\\    The output record separator for the print operator.\r
+$]     The perl version string as displayed with perl -v.\r
+$^     The name of the current top-of-page format.\r
+$^A     The current value of the write() accumulator for format() lines.\r
+$^D    The value of the perl debug (-D) flags.\r
+$^E     Information about the last system error other than that provided by $!.\r
+$^F    The highest system file descriptor, ordinarily 2.\r
+$^H     The current set of syntax checks enabled by `use strict'.\r
+$^I    The value of the in-place edit extension (perl -i option).\r
+$^L     What formats output to perform a formfeed.  Default is \f.\r
+$^M     A buffer for emergency memory allocation when running out of memory.\r
+$^O     The operating system name under which this copy of Perl was built.\r
+$^P    Internal debugging flag.\r
+$^T    The time the script was started.  Used by -A/-M/-C file tests.\r
+$^W    True if warnings are requested (perl -w flag).\r
+$^X    The name under which perl was invoked (argv[0] in C-speech).\r
+$_     The default input and pattern-searching space.\r
+$|     Auto-flush after write/print on current output channel?  Default 0.\r
+$~     The name of the current report format.\r
+... % ...      Modulo division.\r
+... %= ...     Modulo division assignment.\r
+%ENV   Contains the current environment.\r
+%INC   List of files that have been require-d or do-ne.\r
+%SIG   Used to set signal handlers for various signals.\r
+... & ...      Bitwise and.\r
+... && ...     Logical and.\r
+... &&= ...    Logical and assignment.\r
+... &= ...     Bitwise and assignment.\r
+... * ...      Multiplication.\r
+... ** ...     Exponentiation.\r
+*NAME  Glob: all objects refered by NAME.  *NAM1 = *NAM2 aliases NAM1 to NAM2.\r
+&NAME(arg0, ...)       Subroutine call.  Arguments go to @_.\r
+... + ...      Addition.               +EXPR   Makes EXPR into scalar context.\r
+++     Auto-increment (magical on strings).    ++EXPR  EXPR++\r
+... += ...     Addition assignment.\r
+,      Comma operator.\r
+... - ...      Subtraction.\r
+--     Auto-decrement (NOT magical on strings).        --EXPR  EXPR--\r
+... -= ...     Subtraction assignment.\r
+-A     Access time in days since script started.\r
+-B     File is a non-text (binary) file.\r
+-C     Inode change time in days since script started.\r
+-M     Age in days since script started.\r
+-O     File is owned by real uid.\r
+-R     File is readable by real uid.\r
+-S     File is a socket .\r
+-T     File is a text file.\r
+-W     File is writable by real uid.\r
+-X     File is executable by real uid.\r
+-b     File is a block special file.\r
+-c     File is a character special file.\r
+-d     File is a directory.\r
+-e     File exists .\r
+-f     File is a plain file.\r
+-g     File has setgid bit set.\r
+-k     File has sticky bit set.\r
+-l     File is a symbolic link.\r
+-o     File is owned by effective uid.\r
+-p     File is a named pipe (FIFO).\r
+-r     File is readable by effective uid.\r
+-s     File has non-zero size.\r
+-t     Tests if filehandle (STDIN by default) is opened to a tty.\r
+-u     File has setuid bit set.\r
+-w     File is writable by effective uid.\r
+-x     File is executable by effective uid.\r
+-z     File has zero size.\r
+.      Concatenate strings.\r
+..     Range (list context); flip/flop (scalar context) operator.\r
+.=     Concatenate assignment strings\r
+... / ...      Division.       /PATTERN/ioxsmg Pattern match\r
+... /= ...     Division assignment.\r
+/PATTERN/ioxsmg        Pattern match.\r
+... < ...    Numeric less than.        <pattern>       Glob.   See <NAME>, <> as well.\r
+<NAME> Reads line from filehandle NAME (a bareword or dollar-bareword).\r
+<pattern>      Glob (Unless pattern is bareword/dollar-bareword - see <NAME>).\r
+<>     Reads line from union of files in @ARGV (= command line) and STDIN.\r
+... << ...     Bitwise shift left.     <<      start of HERE-DOCUMENT.\r
+... <= ...     Numeric less than or equal to.\r
+... <=> ...    Numeric compare.\r
+... = ...      Assignment.\r
+... == ...     Numeric equality.\r
+... =~ ...     Search pattern, substitution, or translation\r
+... > ...      Numeric greater than.\r
+... >= ...     Numeric greater than or equal to.\r
+... >> ...     Bitwise shift right.\r
+... >>= ...    Bitwise shift right assignment.\r
+... ? ... : ...        Condition=if-then-else operator.   ?PAT? One-time pattern match.\r
+?PATTERN?      One-time pattern match.\r
+@ARGV  Command line arguments (not including the command name - see $0).\r
+@INC   List of places to look for perl scripts during do/include/use.\r
+@_    Parameter array for subroutines; result of split() unless in list context.\r
+\\  Creates reference to what follows, like \$var, or quotes non-\w in strings.\r
+\\0    Octal char, e.g. \\033.\r
+\\E    Case modification terminator.  See \\Q, \\L, and \\U.\r
+\\L    Lowercase until \\E .  See also \l, lc.\r
+\\U    Upcase until \\E .  See also \u, uc.\r
+\\Q    Quote metacharacters until \\E .  See also quotemeta.\r
+\\a    Alarm character (octal 007).\r
+\\b    Backspace character (octal 010).\r
+\\c    Control character, e.g. \\c[ .\r
+\\e    Escape character (octal 033).\r
+\\f    Formfeed character (octal 014).\r
+\\l    Lowercase the next character.  See also \\L and \\u, lcfirst.\r
+\\n    Newline character (octal 012 on most systems).\r
+\\r    Return character (octal 015 on most systems).\r
+\\t    Tab character (octal 011).\r
+\\u    Upcase the next character.  See also \\U and \\l, ucfirst.\r
+\\x    Hex character, e.g. \\x1b.\r
+... ^ ...      Bitwise exclusive or.\r
+__END__        Ends program source.\r
+__DATA__       Ends program source.\r
+__FILE__       Current (source) filename.\r
+__LINE__       Current line in current source.\r
+__PACKAGE__    Current package.\r
+ARGV   Default multi-file input filehandle.  <ARGV> is a synonym for <>.\r
+ARGVOUT        Output filehandle with -i flag.\r
+BEGIN { ... }  Immediately executed (during compilation) piece of code.\r
+END { ... }    Pseudo-subroutine executed after the script finishes.\r
+CHECK { ... }  Pseudo-subroutine executed after the script is compiled.\r
+INIT { ... }   Pseudo-subroutine executed before the script starts running.\r
+DATA   Input filehandle for what follows after __END__ or __DATA__.\r
+accept(NEWSOCKET,GENERICSOCKET)\r
+alarm(SECONDS)\r
+atan2(X,Y)\r
+bind(SOCKET,NAME)\r
+binmode(FILEHANDLE)\r
+caller[(LEVEL)]\r
+chdir(EXPR)\r
+chmod(LIST)\r
+chop[(LIST|VAR)]\r
+chown(LIST)\r
+chroot(FILENAME)\r
+close(FILEHANDLE)\r
+closedir(DIRHANDLE)\r
+... cmp ...    String compare.\r
+connect(SOCKET,NAME)\r
+continue of { block } continue { block }.  Is executed after `next' or at end.\r
+cos(EXPR)\r
+crypt(PLAINTEXT,SALT)\r
+dbmclose(%HASH)\r
+dbmopen(%HASH,DBNAME,MODE)\r
+defined(EXPR)\r
+delete($HASH{KEY})\r
+die(LIST)\r
+do { ... }|SUBR while|until EXPR       executes at least once\r
+do(EXPR|SUBR([LIST]))  (with while|until executes at least once)\r
+dump LABEL\r
+each(%HASH)\r
+endgrent\r
+endhostent\r
+endnetent\r
+endprotoent\r
+endpwent\r
+endservent\r
+eof[([FILEHANDLE])]\r
+... eq ...     String equality.\r
+eval(EXPR) or eval { BLOCK }\r
+exec(LIST)\r
+exit(EXPR)\r
+exp(EXPR)\r
+fcntl(FILEHANDLE,FUNCTION,SCALAR)\r
+fileno(FILEHANDLE)\r
+flock(FILEHANDLE,OPERATION)\r
+for (EXPR;EXPR;EXPR) { ... }\r
+foreach [VAR] (@ARRAY) { ... }\r
+fork\r
+... ge ...     String greater than or equal.\r
+getc[(FILEHANDLE)]\r
+getgrent\r
+getgrgid(GID)\r
+getgrnam(NAME)\r
+gethostbyaddr(ADDR,ADDRTYPE)\r
+gethostbyname(NAME)\r
+gethostent\r
+getlogin\r
+getnetbyaddr(ADDR,ADDRTYPE)\r
+getnetbyname(NAME)\r
+getnetent\r
+getpeername(SOCKET)\r
+getpgrp(PID)\r
+getppid\r
+getpriority(WHICH,WHO)\r
+getprotobyname(NAME)\r
+getprotobynumber(NUMBER)\r
+getprotoent\r
+getpwent\r
+getpwnam(NAME)\r
+getpwuid(UID)\r
+getservbyname(NAME,PROTO)\r
+getservbyport(PORT,PROTO)\r
+getservent\r
+getsockname(SOCKET)\r
+getsockopt(SOCKET,LEVEL,OPTNAME)\r
+gmtime(EXPR)\r
+goto LABEL\r
+... gt ...     String greater than.\r
+hex(EXPR)\r
+if (EXPR) { ... } [ elsif (EXPR) { ... } ... ] [ else { ... } ] or EXPR if EXPR\r
+index(STR,SUBSTR[,OFFSET])\r
+int(EXPR)\r
+ioctl(FILEHANDLE,FUNCTION,SCALAR)\r
+join(EXPR,LIST)\r
+keys(%HASH)\r
+kill(LIST)\r
+last [LABEL]\r
+... le ...     String less than or equal.\r
+length(EXPR)\r
+link(OLDFILE,NEWFILE)\r
+listen(SOCKET,QUEUESIZE)\r
+local(LIST)\r
+localtime(EXPR)\r
+log(EXPR)\r
+lstat(EXPR|FILEHANDLE|VAR)\r
+... lt ...     String less than.\r
+m/PATTERN/iogsmx\r
+mkdir(FILENAME,MODE)\r
+msgctl(ID,CMD,ARG)\r
+msgget(KEY,FLAGS)\r
+msgrcv(ID,VAR,SIZE,TYPE.FLAGS)\r
+msgsnd(ID,MSG,FLAGS)\r
+my VAR or my (VAR1,...)        Introduces a lexical variable ($VAR, @ARR, or %HASH).\r
+our VAR or our (VAR1,...) Lexically enable a global variable ($V, @A, or %H).\r
+... ne ...     String inequality.\r
+next [LABEL]\r
+oct(EXPR)\r
+open(FILEHANDLE[,EXPR])\r
+opendir(DIRHANDLE,EXPR)\r
+ord(EXPR)      ASCII value of the first char of the string.\r
+pack(TEMPLATE,LIST)\r
+package NAME   Introduces package context.\r
+pipe(READHANDLE,WRITEHANDLE)   Create a pair of filehandles on ends of a pipe.\r
+pop(ARRAY)\r
+print [FILEHANDLE] [(LIST)]\r
+printf [FILEHANDLE] (FORMAT,LIST)\r
+push(ARRAY,LIST)\r
+q/STRING/      Synonym for 'STRING'\r
+qq/STRING/     Synonym for \"STRING\"\r
+qx/STRING/     Synonym for `STRING`\r
+rand[(EXPR)]\r
+read(FILEHANDLE,SCALAR,LENGTH[,OFFSET])\r
+readdir(DIRHANDLE)\r
+readlink(EXPR)\r
+recv(SOCKET,SCALAR,LEN,FLAGS)\r
+redo [LABEL]\r
+rename(OLDNAME,NEWNAME)\r
+require [FILENAME | PERL_VERSION]\r
+reset[(EXPR)]\r
+return(LIST)\r
+reverse(LIST)\r
+rewinddir(DIRHANDLE)\r
+rindex(STR,SUBSTR[,OFFSET])\r
+rmdir(FILENAME)\r
+s/PATTERN/REPLACEMENT/gieoxsm\r
+scalar(EXPR)\r
+seek(FILEHANDLE,POSITION,WHENCE)\r
+seekdir(DIRHANDLE,POS)\r
+select(FILEHANDLE | RBITS,WBITS,EBITS,TIMEOUT)\r
+semctl(ID,SEMNUM,CMD,ARG)\r
+semget(KEY,NSEMS,SIZE,FLAGS)\r
+semop(KEY,...)\r
+send(SOCKET,MSG,FLAGS[,TO])\r
+setgrent\r
+sethostent(STAYOPEN)\r
+setnetent(STAYOPEN)\r
+setpgrp(PID,PGRP)\r
+setpriority(WHICH,WHO,PRIORITY)\r
+setprotoent(STAYOPEN)\r
+setpwent\r
+setservent(STAYOPEN)\r
+setsockopt(SOCKET,LEVEL,OPTNAME,OPTVAL)\r
+shift[(ARRAY)]\r
+shmctl(ID,CMD,ARG)\r
+shmget(KEY,SIZE,FLAGS)\r
+shmread(ID,VAR,POS,SIZE)\r
+shmwrite(ID,STRING,POS,SIZE)\r
+shutdown(SOCKET,HOW)\r
+sin(EXPR)\r
+sleep[(EXPR)]\r
+socket(SOCKET,DOMAIN,TYPE,PROTOCOL)\r
+socketpair(SOCKET1,SOCKET2,DOMAIN,TYPE,PROTOCOL)\r
+sort [SUBROUTINE] (LIST)\r
+splice(ARRAY,OFFSET[,LENGTH[,LIST]])\r
+split[(/PATTERN/[,EXPR[,LIMIT]])]\r
+sprintf(FORMAT,LIST)\r
+sqrt(EXPR)\r
+srand(EXPR)\r
+stat(EXPR|FILEHANDLE|VAR)\r
+study[(SCALAR)]\r
+sub [NAME [(format)]] { BODY } sub NAME [(format)];    sub [(format)] {...}\r
+substr(EXPR,OFFSET[,LEN])\r
+symlink(OLDFILE,NEWFILE)\r
+syscall(LIST)\r
+sysread(FILEHANDLE,SCALAR,LENGTH[,OFFSET])\r
+system(LIST)\r
+syswrite(FILEHANDLE,SCALAR,LENGTH[,OFFSET])\r
+tell[(FILEHANDLE)]\r
+telldir(DIRHANDLE)\r
+time\r
+times\r
+tr/SEARCHLIST/REPLACEMENTLIST/cds\r
+truncate(FILE|EXPR,LENGTH)\r
+umask[(EXPR)]\r
+undef[(EXPR)]\r
+unless (EXPR) { ... } [ else { ... } ] or EXPR unless EXPR\r
+unlink(LIST)\r
+unpack(TEMPLATE,EXPR)\r
+unshift(ARRAY,LIST)\r
+until (EXPR) { ... }                                   EXPR until EXPR\r
+utime(LIST)\r
+values(%HASH)\r
+vec(EXPR,OFFSET,BITS)\r
+wait\r
+waitpid(PID,FLAGS)\r
+wantarray      Returns true if the sub/eval is called in list context.\r
+warn(LIST)\r
+while  (EXPR) { ... }                                  EXPR while EXPR\r
+write[(EXPR|FILEHANDLE)]\r
+... x ...      Repeat string or array.\r
+x= ... Repetition assignment.\r
+y/SEARCHLIST/REPLACEMENTLIST/\r
+... | ...      Bitwise or.\r
+... || ...     Logical or.\r
+~ ...          Unary bitwise complement.\r
+#!     OS interpreter indicator.  If contains `perl', used for options, and -x.\r
+AUTOLOAD {...} Shorthand for `sub AUTOLOAD {...}'.\r
+CORE::         Prefix to access builtin function if imported sub obscures it.\r
+SUPER::                Prefix to lookup for a method in @ISA classes.\r
+DESTROY                Shorthand for `sub DESTROY {...}'.\r
+... EQ ...     Obsolete synonym of `eq'.\r
+... GE ...     Obsolete synonym of `ge'.\r
+... GT ...     Obsolete synonym of `gt'.\r
+... LE ...     Obsolete synonym of `le'.\r
+... LT ...     Obsolete synonym of `lt'.\r
+... NE ...     Obsolete synonym of `ne'.\r
+abs [ EXPR ]   absolute value\r
+... and ...            Low-precedence synonym for &&.\r
+bless REFERENCE [, PACKAGE]    Makes reference into an object of a package.\r
+chomp [LIST]   Strips $/ off LIST/$_.  Returns count.  Special if $/ eq ''!\r
+chr            Converts a number to char with the same ordinal.\r
+else           Part of if/unless {BLOCK} elsif {BLOCK} else {BLOCK}.\r
+elsif          Part of if/unless {BLOCK} elsif {BLOCK} else {BLOCK}.\r
+exists $HASH{KEY}      True if the key exists.\r
+format [NAME] =         Start of output format.  Ended by a single dot (.) on a line.\r
+formline PICTURE, LIST Backdoor into \"format\" processing.\r
+glob EXPR      Synonym of <EXPR>.\r
+lc [ EXPR ]    Returns lowercased EXPR.\r
+lcfirst [ EXPR ]       Returns EXPR with lower-cased first letter.\r
+grep EXPR,LIST  or grep {BLOCK} LIST   Filters LIST via EXPR/BLOCK.\r
+map EXPR, LIST or map {BLOCK} LIST     Applies EXPR/BLOCK to elts of LIST.\r
+no PACKAGE [SYMBOL1, ...]  Partial reverse for `use'.  Runs `unimport' method.\r
+not ...                Low-precedence synonym for ! - negation.\r
+... or ...             Low-precedence synonym for ||.\r
+pos STRING    Set/Get end-position of the last match over this string, see \\G.\r
+quotemeta [ EXPR ]     Quote regexp metacharacters.\r
+qw/WORD1 .../          Synonym of split('', 'WORD1 ...')\r
+readline FH    Synonym of <FH>.\r
+readpipe CMD   Synonym of `CMD`.\r
+ref [ EXPR ]   Type of EXPR when dereferenced.\r
+sysopen FH, FILENAME, MODE [, PERM]    (MODE is numeric, see Fcntl.)\r
+tie VAR, PACKAGE, LIST Hide an object behind a simple Perl variable.\r
+tied           Returns internal object for a tied data.\r
+uc [ EXPR ]    Returns upcased EXPR.\r
+ucfirst [ EXPR ]       Returns EXPR with upcased first letter.\r
+untie VAR      Unlink an object from a simple Perl variable.\r
+use PACKAGE [SYMBOL1, ...]  Compile-time `require' with consequent `import'.\r
+... xor ...            Low-precedence synonym for exclusive or.\r
+prototype \&SUB        Returns prototype of the function given a reference.\r
+=head1         Top-level heading.\r
+=head2         Second-level heading.\r
+=head3         Third-level heading (is there such?).\r
+=over [ NUMBER ]       Start list.\r
+=item [ TITLE ]                Start new item in the list.\r
+=back          End list.\r
+=cut           Switch from POD to Perl.\r
+=pod           Switch from Perl to POD.\r
+")\r
+\r
+(defun cperl-switch-to-doc-buffer ()\r
+  "Go to the perl documentation buffer and insert the documentation."\r
+  (interactive)\r
+  (let ((buf (get-buffer-create cperl-doc-buffer)))\r
+    (if (interactive-p)\r
+       (switch-to-buffer-other-window buf)\r
+      (set-buffer buf))\r
+    (if (= (buffer-size) 0)\r
+       (progn\r
+         (insert (documentation-property 'cperl-short-docs\r
+                                         'variable-documentation))\r
+         (setq buffer-read-only t)))))\r
+\r
+(defun cperl-beautify-regexp-piece (b e embed level)\r
+  ;; b is before the starting delimiter, e before the ending\r
+  ;; e should be a marker, may be changed, but remains "correct".\r
+  ;; EMBED is nil iff we process the whole REx.\r
+  ;; The REx is guarantied to have //x\r
+  ;; LEVEL shows how many levels deep to go\r
+  ;; position at enter and at leave is not defined\r
+  (let (s c tmp (m (make-marker)) (m1 (make-marker)) c1 spaces inline code pos)\r
+    (if (not embed)\r
+       (goto-char (1+ b))\r
+      (goto-char b)\r
+      (cond ((looking-at "(\\?\\\\#")  ;  (?#) wrongly commented when //x-ing\r
+            (forward-char 2)\r
+            (delete-char 1)\r
+            (forward-char 1))\r
+           ((looking-at "(\\?[^a-zA-Z]")\r
+            (forward-char 3))\r
+           ((looking-at "(\\?")        ; (?i)\r
+            (forward-char 2))\r
+           (t\r
+            (forward-char 1))))\r
+    (setq c (if embed (current-indentation) (1- (current-column)))\r
+         c1 (+ c (or cperl-regexp-indent-step cperl-indent-level)))\r
+    (or (looking-at "[ \t]*[\n#]")\r
+       (progn\r
+         (insert "\n")))\r
+    (goto-char e)\r
+    (beginning-of-line)\r
+    (if (re-search-forward "[^ \t]" e t)\r
+       (progn                         ; Something before the ending delimiter\r
+         (goto-char e)\r
+         (delete-horizontal-space)\r
+         (insert "\n")\r
+         (indent-to-column c)\r
+         (set-marker e (point))))\r
+    (goto-char b)\r
+    (end-of-line 2)\r
+    (while (< (point) (marker-position e))\r
+      (beginning-of-line)\r
+      (setq s (point)\r
+           inline t)\r
+      (skip-chars-forward " \t")\r
+      (delete-region s (point))\r
+      (indent-to-column c1)\r
+      (while (and\r
+             inline\r
+             (looking-at\r
+              (concat "\\([a-zA-Z0-9]+[^*+{?]\\)" ; 1 word\r
+                      "\\|"            ; Embedded variable\r
+                      "\\$\\([a-zA-Z0-9_]+\\([[{]\\)?\\|[^\n \t)|]\\)" ; 2 3\r
+                      "\\|"            ; $ ^\r
+                      "[$^]"\r
+                      "\\|"            ; simple-code simple-code*?\r
+                      "\\(\\\\.\\|[^][()#|*+?\n]\\)\\([*+{?]\\??\\)?" ; 4 5\r
+                      "\\|"            ; Class\r
+                      "\\(\\[\\)"      ; 6\r
+                      "\\|"            ; Grouping\r
+                      "\\((\\(\\?\\)?\\)" ; 7 8\r
+                      "\\|"            ; |\r
+                      "\\(|\\)")))     ; 9\r
+       (goto-char (match-end 0))\r
+       (setq spaces t)\r
+       (cond ((match-beginning 1)      ; Alphanum word + junk\r
+              (forward-char -1))\r
+             ((or (match-beginning 3)  ; $ab[12]\r
+                  (and (match-beginning 5) ; X* X+ X{2,3}\r
+                       (eq (preceding-char) ?\{)))\r
+              (forward-char -1)\r
+              (forward-sexp 1))\r
+             ((match-beginning 6)      ; []\r
+              (setq tmp (point))\r
+              (if (looking-at "\\^?\\]")\r
+                  (goto-char (match-end 0)))\r
+              ;; XXXX POSIX classes?!\r
+              (while (and (not pos)\r
+                          (re-search-forward "\\[:\\|\\]" e t))\r
+                (if (eq (preceding-char) ?:)\r
+                    (or (re-search-forward ":\\]" e t)\r
+                        (error "[:POSIX:]-group in []-group not terminated"))\r
+                  (setq pos t)))\r
+              (or (eq (preceding-char) ?\])\r
+                  (error "[]-group not terminated"))\r
+              (if (eq (following-char) ?\{)\r
+                  (progn\r
+                    (forward-sexp 1)\r
+                    (and (eq (following-char) ??)\r
+                         (forward-char 1)))\r
+                (re-search-forward "\\=\\([*+?]\\??\\)" e t)))\r
+             ((match-beginning 7)      ; ()\r
+              (goto-char (match-beginning 0))\r
+              (setq pos (current-column))\r
+              (or (eq pos c1)\r
+                  (progn\r
+                    (delete-horizontal-space)\r
+                    (insert "\n")\r
+                    (indent-to-column c1)))\r
+              (setq tmp (point))\r
+              (forward-sexp 1)\r
+              ;;              (or (forward-sexp 1)\r
+              ;;                  (progn\r
+              ;;                    (goto-char tmp)\r
+              ;;                    (error "()-group not terminated")))\r
+              (set-marker m (1- (point)))\r
+              (set-marker m1 (point))\r
+              (if (= level 1)\r
+                  (if (progn           ; indent rigidly if multiline\r
+                        ;; In fact does not make a lot of sense, since\r
+                        ;; the starting position can be already lost due\r
+                        ;; to insertion of "\n" and " "\r
+                        (goto-char tmp)\r
+                        (search-forward "\n" m1 t))\r
+                      (indent-rigidly (point) m1 (- c1 pos)))\r
+                (setq level (1- level))\r
+                (cond\r
+                 ((not (match-beginning 8))\r
+                  (cperl-beautify-regexp-piece tmp m t level))\r
+                 ((eq (char-after (+ 2 tmp)) ?\{) ; Code\r
+                  t)\r
+                 ((eq (char-after (+ 2 tmp)) ?\() ; Conditional\r
+                  (goto-char (+ 2 tmp))\r
+                  (forward-sexp 1)\r
+                  (cperl-beautify-regexp-piece (point) m t level))\r
+                 ((eq (char-after (+ 2 tmp)) ?<) ; Lookbehind\r
+                  (goto-char (+ 3 tmp))\r
+                  (cperl-beautify-regexp-piece (point) m t level))\r
+                 (t\r
+                  (cperl-beautify-regexp-piece tmp m t level))))\r
+              (goto-char m1)\r
+              (cond ((looking-at "[*+?]\\??")\r
+                     (goto-char (match-end 0)))\r
+                    ((eq (following-char) ?\{)\r
+                     (forward-sexp 1)\r
+                     (if (eq (following-char) ?\?)\r
+                         (forward-char))))\r
+              (skip-chars-forward " \t")\r
+              (setq spaces nil)\r
+              (if (looking-at "[#\n]")\r
+                  (progn\r
+                    (or (eolp) (indent-for-comment))\r
+                    (beginning-of-line 2))\r
+                (delete-horizontal-space)\r
+                (insert "\n"))\r
+              (end-of-line)\r
+              (setq inline nil))\r
+             ((match-beginning 9)      ; |\r
+              (forward-char -1)\r
+              (setq tmp (point))\r
+              (beginning-of-line)\r
+              (if (re-search-forward "[^ \t]" tmp t)\r
+                  (progn\r
+                    (goto-char tmp)\r
+                    (delete-horizontal-space)\r
+                    (insert "\n"))\r
+                ;; first at line\r
+                (delete-region (point) tmp))\r
+              (indent-to-column c)\r
+              (forward-char 1)\r
+              (skip-chars-forward " \t")\r
+              (setq spaces nil)\r
+              (if (looking-at "[#\n]")\r
+                  (beginning-of-line 2)\r
+                (delete-horizontal-space)\r
+                (insert "\n"))\r
+              (end-of-line)\r
+              (setq inline nil)))\r
+       (or (looking-at "[ \t\n]")\r
+           (not spaces)\r
+           (insert " "))\r
+       (skip-chars-forward " \t"))\r
+      (or (looking-at "[#\n]")\r
+         (error "Unknown code `%s' in a regexp"\r
+                (buffer-substring (point) (1+ (point)))))\r
+      (and inline (end-of-line 2)))\r
+    ;; Special-case the last line of group\r
+    (if (and (>= (point) (marker-position e))\r
+            (/= (current-indentation) c))\r
+       (progn\r
+         (beginning-of-line)\r
+         (setq s (point))\r
+         (skip-chars-forward " \t")\r
+         (delete-region s (point))\r
+         (indent-to-column c)))))\r
+\r
+(defun cperl-make-regexp-x ()\r
+  ;; Returns position of the start\r
+  ;; XXX this is called too often!  Need to cache the result!\r
+  (save-excursion\r
+    (or cperl-use-syntax-table-text-property\r
+       (error "I need to have a regexp marked!"))\r
+    ;; Find the start\r
+    (if (looking-at "\\s|")\r
+       nil                             ; good already\r
+      (if (looking-at "\\([smy]\\|qr\\)\\s|")\r
+         (forward-char 1)\r
+       (re-search-backward "\\s|")))   ; Assume it is scanned already.\r
+    ;;(forward-char 1)\r
+    (let ((b (point)) (e (make-marker)) have-x delim (c (current-column))\r
+         (sub-p (eq (preceding-char) ?s)) s)\r
+      (forward-sexp 1)\r
+      (set-marker e (1- (point)))\r
+      (setq delim (preceding-char))\r
+      (if (and sub-p (eq delim (char-after (- (point) 2))))\r
+         (error "Possible s/blah// - do not know how to deal with"))\r
+      (if sub-p (forward-sexp 1))\r
+      (if (looking-at "\\sw*x")\r
+         (setq have-x t)\r
+       (insert "x"))\r
+      ;; Protect fragile " ", "#"\r
+      (if have-x nil\r
+       (goto-char (1+ b))\r
+       (while (re-search-forward "\\(\\=\\|[^\\\\]\\)\\(\\\\\\\\\\)*[ \t\n#]" e t) ; Need to include (?#) too?\r
+         (forward-char -1)\r
+         (insert "\\")\r
+         (forward-char 1)))\r
+      b)))\r
+\r
+(defun cperl-beautify-regexp (&optional deep)\r
+  "Do it.  (Experimental, may change semantics, recheck the result.)\r
+We suppose that the regexp is scanned already."\r
+  (interactive "P")\r
+  (setq deep (if deep (prefix-numeric-value deep) -1))\r
+  (save-excursion\r
+    (goto-char (cperl-make-regexp-x))\r
+    (let ((b (point)) (e (make-marker)))\r
+      (forward-sexp 1)\r
+      (set-marker e (1- (point)))\r
+      (cperl-beautify-regexp-piece b e nil deep))))\r
+\r
+(defun cperl-regext-to-level-start ()\r
+  "Goto start of an enclosing group in regexp.\r
+We suppose that the regexp is scanned already."\r
+  (interactive)\r
+  (let ((limit (cperl-make-regexp-x)) done)\r
+    (while (not done)\r
+      (or (eq (following-char) ?\()\r
+         (search-backward "(" (1+ limit) t)\r
+         (error "Cannot find `(' which starts a group"))\r
+      (setq done\r
+           (save-excursion\r
+             (skip-chars-backward "\\")\r
+             (looking-at "\\(\\\\\\\\\\)*(")))\r
+      (or done (forward-char -1)))))\r
+\r
+(defun cperl-contract-level ()\r
+  "Find an enclosing group in regexp and contract it.\r
+\(Experimental, may change semantics, recheck the result.)\r
+We suppose that the regexp is scanned already."\r
+  (interactive)\r
+  ;; (save-excursion           ; Can't, breaks `cperl-contract-levels'\r
+  (cperl-regext-to-level-start)\r
+  (let ((b (point)) (e (make-marker)) s c)\r
+    (forward-sexp 1)\r
+    (set-marker e (1- (point)))\r
+    (goto-char b)\r
+    (while (re-search-forward "\\(#\\)\\|\n" e 'to-end)\r
+      (cond\r
+       ((match-beginning 1)            ; #-comment\r
+       (or c (setq c (current-indentation)))\r
+       (beginning-of-line 2)           ; Skip\r
+       (setq s (point))\r
+       (skip-chars-forward " \t")\r
+       (delete-region s (point))\r
+       (indent-to-column c))\r
+       (t\r
+       (delete-char -1)\r
+       (just-one-space))))))\r
+\r
+(defun cperl-contract-levels ()\r
+  "Find an enclosing group in regexp and contract all the kids.\r
+\(Experimental, may change semantics, recheck the result.)\r
+We suppose that the regexp is scanned already."\r
+  (interactive)\r
+  (save-excursion\r
+    (condition-case nil\r
+       (cperl-regext-to-level-start)\r
+      (error                           ; We are outside outermost group\r
+       (goto-char (cperl-make-regexp-x))))\r
+    (let ((b (point)) (e (make-marker)) s c)\r
+      (forward-sexp 1)\r
+      (set-marker e (1- (point)))\r
+      (goto-char (1+ b))\r
+      (while (re-search-forward "\\(\\\\\\\\\\)\\|(" e t)\r
+       (cond\r
+        ((match-beginning 1)           ; Skip\r
+         nil)\r
+        (t                             ; Group\r
+         (cperl-contract-level)))))))\r
+\r
+(defun cperl-beautify-level (&optional deep)\r
+  "Find an enclosing group in regexp and beautify it.\r
+\(Experimental, may change semantics, recheck the result.)\r
+We suppose that the regexp is scanned already."\r
+  (interactive "P")\r
+  (setq deep (if deep (prefix-numeric-value deep) -1))\r
+  (save-excursion\r
+    (cperl-regext-to-level-start)\r
+    (let ((b (point)) (e (make-marker)))\r
+      (forward-sexp 1)\r
+      (set-marker e (1- (point)))\r
+      (cperl-beautify-regexp-piece b e nil deep))))\r
+\r
+(defun cperl-invert-if-unless ()\r
+  "Change `if (A) {B}' into `B if A;' etc if possible."\r
+  (interactive)\r
+  (or (looking-at "\\<")\r
+      (forward-sexp -1))\r
+  (if (looking-at "\\<\\(if\\|unless\\|while\\|until\\|for\\|foreach\\)\\>")\r
+      (let ((pos1 (point))\r
+           pos2 pos3 pos4 pos5 s1 s2 state p pos45\r
+           (s0 (buffer-substring (match-beginning 0) (match-end 0))))\r
+       (forward-sexp 2)\r
+       (setq pos3 (point))\r
+       (forward-sexp -1)\r
+       (setq pos2 (point))\r
+       (if (eq (following-char) ?\( )\r
+           (progn\r
+             (goto-char pos3)\r
+             (forward-sexp 1)\r
+             (setq pos5 (point))\r
+             (forward-sexp -1)\r
+             (setq pos4 (point))\r
+             ;; XXXX In fact may be `A if (B); {C}' ...\r
+             (if (and (eq (following-char) ?\{ )\r
+                      (progn\r
+                        (cperl-backward-to-noncomment pos3)\r
+                        (eq (preceding-char) ?\) )))\r
+                 (if (condition-case nil\r
+                         (progn\r
+                           (goto-char pos5)\r
+                           (forward-sexp 1)\r
+                           (forward-sexp -1)\r
+                           (looking-at "\\<els\\(e\\|if\\)\\>"))\r
+                       (error nil))\r
+                     (error\r
+                      "`%s' (EXPR) {BLOCK} with `else'/`elsif'" s0)\r
+                   (goto-char (1- pos5))\r
+                   (cperl-backward-to-noncomment pos4)\r
+                   (if (eq (preceding-char) ?\;)\r
+                       (forward-char -1))\r
+                   (setq pos45 (point))\r
+                   (goto-char pos4)\r
+                   (while (re-search-forward "\\<\\(for\\|foreach\\|if\\|unless\\|while\\|until\\)\\>\\|;" pos45 t)\r
+                     (setq p (match-beginning 0)\r
+                           s1 (buffer-substring p (match-end 0))\r
+                           state (parse-partial-sexp pos4 p))\r
+                     (or (nth 3 state)\r
+                         (nth 4 state)\r
+                         (nth 5 state)\r
+                         (error "`%s' inside `%s' BLOCK" s1 s0))\r
+                     (goto-char (match-end 0)))\r
+                   ;; Finally got it\r
+                   (goto-char (1+ pos4))\r
+                   (skip-chars-forward " \t\n")\r
+                   (setq s2 (buffer-substring (point) pos45))\r
+                   (goto-char pos45)\r
+                   (or (looking-at ";?[ \t\n]*}")\r
+                       (progn\r
+                         (skip-chars-forward "; \t\n")\r
+                         (setq s2 (concat s2 "\n" (buffer-substring (point) (1- pos5))))))\r
+                   (and (equal s2 "")\r
+                        (setq s2 "1"))\r
+                   (goto-char (1- pos3))\r
+                   (cperl-backward-to-noncomment pos2)\r
+                   (or (looking-at "[ \t\n]*)")\r
+                       (goto-char (1- pos3)))\r
+                   (setq p (point))\r
+                   (goto-char (1+ pos2))\r
+                   (skip-chars-forward " \t\n")\r
+                   (setq s1 (buffer-substring (point) p))\r
+                   (delete-region pos4 pos5)\r
+                   (delete-region pos2 pos3)\r
+                   (goto-char pos1)\r
+                   (insert s2 " ")\r
+                   (just-one-space)\r
+                   (forward-word 1)\r
+                   (setq pos1 (point))\r
+                   (insert " " s1 ";")\r
+                   (delete-horizontal-space)\r
+                   (forward-char -1)\r
+                   (delete-horizontal-space)\r
+                   (goto-char pos1)\r
+                   (just-one-space)\r
+                   (cperl-indent-line))\r
+               (error "`%s' (EXPR) not with an {BLOCK}" s0)))\r
+         (error "`%s' not with an (EXPR)" s0)))\r
+    (error "Not at `if', `unless', `while', `until', `for' or `foreach'")))\r
+\r
+;;; By Anthony Foiani <afoiani@uswest.com>\r
+;;; Getting help on modules in C-h f ?\r
+;;; This is a modified version of `man'.\r
+;;; Need to teach it how to lookup functions\r
+(defun cperl-perldoc (word)\r
+  "Run `perldoc' on WORD."\r
+  (interactive\r
+   (list (let* ((default-entry (cperl-word-at-point))\r
+                (input (read-string\r
+                        (format "perldoc entry%s: "\r
+                                (if (string= default-entry "")\r
+                                    ""\r
+                                  (format " (default %s)" default-entry))))))\r
+           (if (string= input "")\r
+               (if (string= default-entry "")\r
+                   (error "No perldoc args given")\r
+                 default-entry)\r
+             input))))\r
+  (require 'man)\r
+  (let* ((case-fold-search nil)\r
+        (is-func (and\r
+                  (string-match "^[a-z]+$" word)\r
+                  (string-match (concat "^" word "\\>")\r
+                                (documentation-property\r
+                                 'cperl-short-docs\r
+                                 'variable-documentation))))\r
+        (manual-program (if is-func "perldoc -f" "perldoc")))\r
+    (cond\r
+     (cperl-xemacs-p\r
+      (let ((Manual-program "perldoc")\r
+           (Manual-switches (if is-func (list "-f"))))\r
+       (manual-entry word)))\r
+     (t\r
+      (Man-getpage-in-background word)))))\r
+\r
+(defun cperl-perldoc-at-point ()\r
+  "Run a `perldoc' on the word around point."\r
+  (interactive)\r
+  (cperl-perldoc (cperl-word-at-point)))\r
+\r
+(defcustom pod2man-program "pod2man"\r
+  "*File name for `pod2man'."\r
+  :type 'file\r
+  :group 'cperl)\r
+\r
+;;; By Nick Roberts <Nick.Roberts@src.bae.co.uk> (with changes)\r
+(defun cperl-pod-to-manpage ()\r
+  "Create a virtual manpage in Emacs from the Perl Online Documentation."\r
+  (interactive)\r
+  (require 'man)\r
+  (let* ((pod2man-args (concat buffer-file-name " | nroff -man "))\r
+        (bufname (concat "Man " buffer-file-name))\r
+        (buffer (generate-new-buffer bufname)))\r
+    (save-excursion\r
+      (set-buffer buffer)\r
+      (let ((process-environment (copy-sequence process-environment)))\r
+        ;; Prevent any attempt to use display terminal fanciness.\r
+        (setenv "TERM" "dumb")\r
+        (set-process-sentinel\r
+         (start-process pod2man-program buffer "sh" "-c"\r
+                        (format (cperl-pod2man-build-command) pod2man-args))\r
+         'Man-bgproc-sentinel)))))\r
+\r
+;;; Updated version by him too\r
+(defun cperl-build-manpage ()\r
+  "Create a virtual manpage in Emacs from the POD in the file."\r
+  (interactive)\r
+  (require 'man)\r
+  (cond\r
+   (cperl-xemacs-p\r
+    (let ((Manual-program "perldoc"))\r
+      (manual-entry buffer-file-name)))\r
+   (t\r
+    (let* ((manual-program "perldoc"))\r
+      (Man-getpage-in-background buffer-file-name)))))\r
+\r
+(defun cperl-pod2man-build-command ()\r
+  "Builds the entire background manpage and cleaning command."\r
+  (let ((command (concat pod2man-program " %s 2>/dev/null"))\r
+        (flist Man-filter-list))\r
+    (while (and flist (car flist))\r
+      (let ((pcom (car (car flist)))\r
+            (pargs (cdr (car flist))))\r
+        (setq command\r
+              (concat command " | " pcom " "\r
+                      (mapconcat '(lambda (phrase)\r
+                                    (if (not (stringp phrase))\r
+                                        (error "Malformed Man-filter-list"))\r
+                                    phrase)\r
+                                 pargs " ")))\r
+        (setq flist (cdr flist))))\r
+    command))\r
+\r
+(defun cperl-lazy-install ())          ; Avoid a warning\r
+(defun cperl-lazy-unstall ())          ; Avoid a warning\r
+\r
+(if (fboundp 'run-with-idle-timer)\r
+    (progn\r
+      (defvar cperl-help-shown nil\r
+       "Non-nil means that the help was already shown now.")\r
+\r
+      (defvar cperl-lazy-installed nil\r
+       "Non-nil means that the lazy-help handlers are installed now.")\r
+\r
+      (defun cperl-lazy-install ()\r
+       "Switches on Auto-Help on Perl constructs (put in the message area).\r
+Delay of auto-help controlled by `cperl-lazy-help-time'."\r
+       (interactive)\r
+       (make-variable-buffer-local 'cperl-help-shown)\r
+       (if (and (cperl-val 'cperl-lazy-help-time)\r
+                (not cperl-lazy-installed))\r
+           (progn\r
+             (add-hook 'post-command-hook 'cperl-lazy-hook)\r
+             (run-with-idle-timer\r
+              (cperl-val 'cperl-lazy-help-time 1000000 5)\r
+              t\r
+              'cperl-get-help-defer)\r
+             (setq cperl-lazy-installed t))))\r
+\r
+      (defun cperl-lazy-unstall ()\r
+       "Switches off Auto-Help on Perl constructs (put in the message area).\r
+Delay of auto-help controlled by `cperl-lazy-help-time'."\r
+       (interactive)\r
+       (remove-hook 'post-command-hook 'cperl-lazy-hook)\r
+       (cancel-function-timers 'cperl-get-help-defer)\r
+       (setq cperl-lazy-installed nil))\r
+\r
+      (defun cperl-lazy-hook ()\r
+       (setq cperl-help-shown nil))\r
+\r
+      (defun cperl-get-help-defer ()\r
+       (if (not (memq major-mode '(perl-mode cperl-mode))) nil\r
+         (let ((cperl-message-on-help-error nil) (cperl-help-from-timer t))\r
+           (cperl-get-help)\r
+           (setq cperl-help-shown t))))\r
+      (cperl-lazy-install)))\r
+\r
+\r
+;;; Plug for wrong font-lock:\r
+\r
+(defun cperl-font-lock-unfontify-region-function (beg end)\r
+  (let* ((modified (buffer-modified-p)) (buffer-undo-list t)\r
+        (inhibit-read-only t) (inhibit-point-motion-hooks t)\r
+        before-change-functions after-change-functions\r
+        deactivate-mark buffer-file-name buffer-file-truename)\r
+    (remove-text-properties beg end '(face nil))\r
+    (when (and (not modified) (buffer-modified-p))\r
+      (set-buffer-modified-p nil))))\r
+\r
+(defvar cperl-d-l nil)\r
+(defun cperl-fontify-syntaxically (end)\r
+  ;; Some vars for debugging only\r
+  ;; (message "Syntaxifying...")\r
+  (let ((dbg (point)) (iend end)\r
+       (istate (car cperl-syntax-state))\r
+       start)\r
+    (and cperl-syntaxify-unwind\r
+        (setq end (cperl-unwind-to-safe t end)))\r
+    (setq start (point))\r
+    (or cperl-syntax-done-to\r
+       (setq cperl-syntax-done-to (point-min)))\r
+    (if (or (not (boundp 'font-lock-hot-pass))\r
+           (eval 'font-lock-hot-pass)\r
+           t)                          ; Not debugged otherwise\r
+       ;; Need to forget what is after `start'\r
+       (setq start (min cperl-syntax-done-to start))\r
+      ;; Fontification without a change\r
+      (setq start (max cperl-syntax-done-to start)))\r
+    (and (> end start)\r
+        (setq cperl-syntax-done-to start) ; In case what follows fails\r
+        (cperl-find-pods-heres start end t nil t))\r
+    (if (eq cperl-syntaxify-by-font-lock 'message)\r
+       (message "Syntaxified %s..%s from %s to %s(%s), state %s-->%s"\r
+                dbg iend\r
+                start end cperl-syntax-done-to\r
+                istate (car cperl-syntax-state))) ; For debugging\r
+    nil))                              ; Do not iterate\r
+\r
+(defun cperl-fontify-update (end)\r
+  (let ((pos (point)) prop posend)\r
+    (while (< pos end)\r
+      (setq prop (get-text-property pos 'cperl-postpone))\r
+      (setq posend (next-single-property-change pos 'cperl-postpone nil end))\r
+      (and prop (put-text-property pos posend (car prop) (cdr prop)))\r
+      (setq pos posend)))\r
+  nil)                                 ; Do not iterate\r
+\r
+(defun cperl-update-syntaxification (from to)\r
+  (if (and cperl-use-syntax-table-text-property\r
+          cperl-syntaxify-by-font-lock\r
+          (or (null cperl-syntax-done-to)\r
+              (< cperl-syntax-done-to to)))\r
+      (progn\r
+       (save-excursion\r
+         (goto-char from)\r
+         (cperl-fontify-syntaxically to)))))\r
+\r
+(defvar cperl-version\r
+  (let ((v  "$Revision: 5.0 $"))\r
+    (string-match ":\\s *\\([0-9.]+\\)" v)\r
+    (substring v (match-beginning 1) (match-end 1)))\r
+  "Version of IZ-supported CPerl package this file is based on.")\r
+\r
+(provide 'cperl-mode)\r
+\r
+;;; cperl-mode.el ends here\r
diff --git a/emacs_el/crontab-mode.el b/emacs_el/crontab-mode.el
new file mode 100644 (file)
index 0000000..0f9ef22
--- /dev/null
@@ -0,0 +1,227 @@
+;;; crontab-mode.el --- Mode for editing crontab files
+;;
+;; ~/share/emacs/pkg/crontab/crontab-mode.el ---
+;;
+;; $Id: crontab-mode.el,v 1.18 2004/03/10 06:51:59 harley Exp $
+;;
+
+;; Author:    Harley Gorrell <harley@mahalito.net>
+;; URL:       http://www.mahalito.net/~harley/elisp/crontab-mode.el
+;; License:   GPL v2
+;; Keywords: cron, crontab, emacs
+
+;;; Commentary:
+;; * I want to keep my crontabs under rcs to keep a history of
+;;   the file.  Editing them with 'crontab -e' is rather
+;;   cumbersome.  My method is to keep the crontab as a file,
+;;   under rcs, and check in the changes with 'C-c C-c' after
+;;   editing.
+;; 
+;; * The remote systems are expected to share a filesystem.
+;;   If they dont, modify crontab-shell or crontab-apply to
+;;   suit your needs.
+;;
+;; * You may want to add one of these to your startup:
+;;   (add-to-list 'auto-mode-alist '("\\.cron\\(tab\\)?\\'" . crontab-mode))
+;;   (add-to-list 'auto-mode-alist '("cron\\(tab\\)?\\."    . crontab-mode))
+
+;;; History:
+;;  2003-03-16: Updated URL and contact info
+;;  2004-02-26: Use ssh to apply crontabs to remote hosts.
+
+;;; Code:
+
+(defvar crontab-suffix ".crontab"
+  "*Suffix for crontab buffers.")
+
+(defvar crontab-apply-after-save nil
+  "*Non-nil to apply the crontab after a save.")
+(make-variable-buffer-local 'crontab-apply-after-save)
+
+(defvar crontab-host nil
+  "*Hostname to use when saving the crontab to a remote host.")
+(make-variable-buffer-local 'crontab-host)
+
+(defvar crontab-user nil
+  "*Username to use when saving the crontab to a remote host.")
+(make-variable-buffer-local 'crontab-user)
+
+;; Would be better to have "\\([0-9]\\([-,][0-9]+\\)+\\|...
+(defvar crontab-unit-regexp "\\([-,0-9]+\\|\\*\\)"
+  "A regexp which matches a cron time unit.")
+
+(defvar crontab-sep-regexp "[ \t]+"
+  "A regexp to match whitespace seperating cron time units.")
+
+(defvar crontab-ruler "
+# min   hour    day     month   day-of-week command
+#(0-59) (0-23)  (1-31)  (1-12)  (0-6)
+#
+#------------------------------------------------------------
+"
+  "*The ruler `crontab-insert-ruler' inserts.")
+
+;;
+(defvar crontab-mode-hook nil
+  "*Hook for customising `crontab-mode'.")
+
+(defvar crontab-load-hook nil
+  "*Hook run when the `crontab-mode' is loaded.")
+
+;;
+(defvar crontab-font-lock-keywords
+  (list
+   ;; Comments
+   '("^#.*$" . font-lock-comment-face)
+   ;; Blank lines are bad!
+   '("^[ \t]+$" . highlight)
+   ;; Variable defs
+   '("^\\([A-Z_]+\\)=\\(.*\\)$" .
+     ((1 font-lock-keyword-face)
+      (2 font-lock-string-face)) )
+   ;; Cron lines
+   ;; 50 * * * * /usr/gnu/bin/bash
+   (cons
+    (concat "^"
+           crontab-unit-regexp crontab-sep-regexp
+           crontab-unit-regexp crontab-sep-regexp
+           crontab-unit-regexp crontab-sep-regexp
+           crontab-unit-regexp crontab-sep-regexp
+           crontab-unit-regexp crontab-sep-regexp
+           "\\(.*\\)$")
+    '((1 font-lock-keyword-face)
+      (2 font-lock-keyword-face)
+      (3 font-lock-keyword-face)
+      (4 font-lock-keyword-face)
+      (5 font-lock-keyword-face)
+      (6 font-lock-string-face))) )
+  "Info for function `font-lock-mode'.")
+
+(defvar crontab-mode-map nil
+  "Keymap used in `crontab-mode'.")
+
+(if crontab-mode-map
+  ()
+  (setq crontab-mode-map (make-sparse-keymap))
+  (define-key crontab-mode-map "\C-c\C-c" 'crontab-save-and-apply)
+  (define-key crontab-mode-map "\C-cc" 'crontab-save-and-apply)
+  (define-key crontab-mode-map "\C-ca" 'crontab-save-and-apply-to)
+  (define-key crontab-mode-map "\C-ci" 'crontab-insert-local-var)
+  (define-key crontab-mode-map "\C-cr" 'crontab-insert-ruler))
+
+;; This will barf without the correct agent or key setup.
+(defvar crontab-rsh-cmd "ssh" ;; "rsh"
+  "Program to use for remote shells.")
+
+(defun crontab-rsh-cmd ()
+  "Generate the rsh command.  Redefine as needed."
+  (if crontab-user
+    (concat crontab-rsh-cmd " -l " (format "%s" crontab-user)) ;; str-ify
+    crontab-rsh-cmd) )
+
+(defun crontab-localhost-p (&optional host)
+  "True if this is the same HOST Emacs is on."
+  (or (null host)
+      (string= host "")
+      (string= host "localhost")
+      (string= host (system-name))) )
+
+(defun crontab-shell (host cmd out-buffer)
+  "On a possibly remote HOST, run CMD  Output to OUT-BUFFER."
+  (when (not (crontab-localhost-p host))
+    (setq cmd (concat (crontab-rsh-cmd) " " host " " cmd)))
+  (shell-command cmd out-buffer) )
+
+;;;###autoload
+(defun crontab-mode ()
+  "Major mode for editing crontabs.
+Defines commands for getting and applying crontabs for hosts.
+Sets up command `font-lock-mode'.
+
+\\{crontab-mode-map}"
+  (interactive)
+  ;;
+  (kill-all-local-variables)
+  (setq mode-name "crontab")
+  (setq major-mode 'crontab-mode)
+  (use-local-map crontab-mode-map)
+  ;;
+  (setq comment-start "#")
+  (setq comment-start-skip "#+ *")
+  ;;
+  (make-local-variable 'font-lock-defaults)
+  (setq font-lock-defaults '(crontab-font-lock-keywords))
+  ;; Add to the end of the buffers save hooks.
+  (add-hook 'after-save-hook 'crontab-after-save t t)
+  ;;
+  (run-hooks 'crontab-mode-hook) )
+
+
+;;;###autoload
+(defun crontab-get (host)
+  "Get the crontab for the HOST into a buffer."
+  (interactive "sCrontab for host:")
+  (let ((cbn (generate-new-buffer-name (concat host crontab-suffix))))
+    (switch-to-buffer-other-window cbn)
+    (erase-buffer)
+    (crontab-mode)
+    (crontab-insert host)
+    (not-modified)
+    (setq crontab-host host)) )
+
+(defun crontab-insert (&optional host)
+  "Insert the crontab for the HOST into the current buffer."
+  (crontab-shell host "crontab -l" t) )
+
+(defun crontab-apply (&optional host)
+  "Apply the crontab to a HOST.  The filesystem must be common."
+  (if (buffer-file-name)
+    (crontab-shell host (concat "crontab " (buffer-file-name)) nil)
+    (error "No filename  for this buffer")))
+
+(defun crontab-save-and-apply ()
+  "Save and apply the buffer to the HOST."
+  (interactive)
+  (save-buffer)
+  (if (not crontab-apply-after-save) ;; Dont apply it twice.
+    (crontab-apply (crontab-host))) )
+
+(defun crontab-save-and-apply-to (host)
+  "Prompt for the HOST and apply the file."
+  (interactive "sApply to host:")
+  (setq crontab-host host) ;; remember the change
+  (crontab-save-and-apply) )
+
+(defun crontab-insert-ruler ()
+  "Insert a ruler with comments into the crontab."
+  (interactive)
+  (end-of-line)
+  (insert crontab-ruler) )
+
+(defun crontab-insert-local-var ()
+  "Insert the current values of buffer local variables."
+  (interactive)
+  (end-of-buffer)
+  (insert "
+" comment-start " Local " "Variables:
+" comment-start " mode: " (format "%s" (or mode-name "crontab")) "
+" comment-start " crontab-host: " (crontab-host) "
+" comment-start " crontab-apply-after-save: "
+(format "%s" crontab-apply-after-save) "
+" comment-start " End:
+") )
+
+(defun crontab-host ()
+  "Return the hostname as a string, defaulting to the local host.
+The variable `crontab-host' could be a symbol or a string."
+  (format "%s" (or crontab-host system-name)) )
+
+;;
+(defun crontab-after-save ()
+  "If `crontab-apply-after-save' is set, apply the crontab after a save."
+  (if crontab-apply-after-save (crontab-apply (crontab-host))) )
+
+(provide 'crontab-mode)
+(run-hooks 'crontab-load-hook)
+
+;;; crontab-mode.el ends here
diff --git a/emacs_el/dna-mode.el b/emacs_el/dna-mode.el
new file mode 100644 (file)
index 0000000..5433ea1
--- /dev/null
@@ -0,0 +1,590 @@
+;;; dna-mode.el --- a major mode for editing dna sequences
+;;
+;; ~harley/share/emacs/pkg/dna/dna-mode.el ---
+;;
+;; $Id: dna-mode.el,v 1.40 2004/04/20 19:03:04 harley Exp $
+;;
+
+;; Author:    Harley Gorrell <harley@panix.com>
+;; URL:       http://www.mahalito.net/~harley/elisp/dna-mode.el
+;; License:   GPL v2
+;; Keywords:  dna, emacs, editing
+
+;;; Commentary:
+;; * A collection of functions for editing DNA sequences.  It
+;;   provides functions to make editing dna in Emacs easier.
+;;
+;; Dna-mode will:
+;;  * Fontify keywords and line numbers in sequences.
+;;  * Fontify bases when font-lock-mode is disabled.
+;;  * Incrementally search dna over pads and numbers.
+;;  * Complement and reverse complement a region.
+;;  * Move over bases and entire sequences.
+;;  * Detect sequence files by content.
+
+;;; Installation:
+;; --------------------
+;; Here are two suggested ways for installing this package.
+;; You can choose to autoload it when needed, or load it
+;; each time emacs is started.  Put one of the following
+;; sections in your .emacs:
+;;
+;; ---Autoload:
+;;  (autoload 'dna-mode "dna-mode" "Major mode for dna" t)
+;;  (add-to-list
+;;     'auto-mode-alist
+;;     '("\\.\\(fasta\\|fa\\|exp\\|ace\\|gb\\)\\'" . dna-mode))
+;;  (add-hook 'dna-mode-hook 'turn-on-font-lock)
+;;
+;; ---Load:
+;;  (setq dna-do-setup-on-load t)
+;;  (load "/pathname/dna-mode")
+;;
+;; The dna-isearch-forward function (and isearch in general)
+;; is much more useful with something like the following:
+;;  (make-face 'isearch)
+;;  (set-face-background 'isearch "yellow")
+;;  (setq-default search-highlight t)
+
+;;; History:
+;;  2003-03-16: Updated URL and contact info
+;;  2004-04-20: Added dna-color-bases-region to the keymap for Mike.
+
+;;; User customizable vars start here
+
+;;; Code:
+(defvar dna-mode-hook nil
+  "*Hook to setup `dna-mode'.")
+
+(defvar dna-mode-load-hook nil
+  "*Hook to run when `dna-mode' is loaded.")
+
+(defvar dna-setup-on-load nil
+  "*If not nil setup dna mode on load by running `dna-`add-hook's'.")
+
+;; Bases
+(defvar dna-valid-base-regexp
+  "[-*:acgtmrwsykvhdbxnACGTMRWSYKVHDBXN]"
+  "*A regexp which matches a single base.")
+
+(defvar dna-base-complement-list
+  '((?- . ?-) (?n . ?n) (?* . ?*) (?x . ?x) (?: . ?:) ; identity
+    (?a . ?t) (?c . ?g) (?g . ?c) (?t . ?a) ; single
+    (?m . ?k) (?r . ?y) (?w . ?w) (?s . ?s) (?y . ?r) (?k . ?m) ; double
+    (?v . ?b) (?h . ?d) (?d . ?h) (?b . ?v) ; triple
+    )
+  "*List of bases and their complements.
+Bases should be lowercase, as they are upcased when the `vector is made.")
+
+;; These are the colors used when coloring bases.
+(defvar dna-base-color-a "blue")
+(defvar dna-base-color-c "black")
+(defvar dna-base-color-g "green")
+(defvar dna-base-color-t "red")
+
+;; Dna-isearch
+(defvar dna-cruft-regexp "[* 0-9\t\n]"
+  "*Regexp to match cruft which may appear between bases.
+Skip over it during dna-motion and dna-isearch.")
+
+(defvar dna-isearch-case-fold-search t
+  "*Case fold dna-isearches if set.")
+
+;; Sequence
+(defvar dna-sequence-start-regexp
+  "^\\(>\\|ID\\|LOCUS\\|DNA\\)"
+  "A regexp which matches the start of a sequence.")
+
+;;; End of user customizable vars
+
+;;; Start of internal vars and code
+
+(defvar dna-base-complement-vector
+  (let ((c-vec (make-vector 256 nil))
+       (c-list dna-base-complement-list))
+    (while c-list
+      (aset c-vec (car (car c-list)) (cdr (car c-list)))
+      (aset c-vec (upcase (car (car c-list))) (upcase (cdr (car c-list))))
+      (setq c-list (cdr c-list)))
+    c-vec)
+  "A vector of upper and lower case bases and their complements.")
+
+;; I also use "Alt" as C-c is too much to type for cursor motions.
+(defvar dna-mode-map
+  (let ((map (make-sparse-keymap)))
+    ;; Ctrl bindings
+    (define-key map "\C-c\C-f" 'dna-forward-base)
+    (define-key map "\C-cf"    'dna-forward-base)
+    (define-key map "\C-c\C-b" 'dna-backward-base)
+    (define-key map "\C-cb"    'dna-backward-base)
+    (define-key map "\C-c\C-s" 'dna-isearch-forward)
+    (define-key map "\C-cs"    'dna-isearch-forward)
+    (define-key map "\C-cr"    'dna-reverse-complement-region)
+    (define-key map "\C-cc"    'dna-complement-region)
+    (define-key map "\C-c#"    'dna-count-bases-region)
+    (define-key map "\M-\C-h"  'dna-mark-sequence)
+    (define-key map "\M-\C-a"  'dna-beginning-of-sequence)
+    (define-key map "\M-\C-e"  'dna-end-of-sequence)
+    ;; base coloring
+    (define-key map "\C-cg"     'dna-color-bases-region)
+    (define-key map "\C-cl"     'font-lock-mode)
+    ;; XEmacs does not like the Alt bindings
+    (when (not (string-match "XEmacs" (emacs-version)))
+      (define-key map [A-right]        'dna-forward-base)
+      (define-key map [A-left] 'dna-backward-base)
+      (define-key map [A-up]   'dna-beginning-of-sequence)
+      (define-key map [A-down] 'dna-end-of-sequence)
+      (define-key map [?\A-\C-s]       'dna-isearch-forward))
+    map)
+  "The local keymap for `dna-mode'.")
+
+;;;###autoload
+(defun dna-mode ()
+  "Major mode for editing DNA sequences.
+
+This mode also customizes isearch to search over line breaks.
+Use \\[universal-argument] Number as a prefix to dna-forward-base to move that
+many bases.  This skips line breaks and spaces.
+
+dna-color-bases-region disables font-lock-mode automaticly
+as they cant work together. \\[dna-color-bases-region] turns font-lock-mode back on.
+
+\\{dna-mode-map}"
+  (interactive)
+  ;;
+  (kill-all-local-variables)
+  (setq mode-name "dna")
+  (setq major-mode 'dna-mode)
+  (use-local-map dna-mode-map)
+  ;;
+  (make-local-variable 'font-lock-defaults)
+  (setq font-lock-defaults '(dna-font-lock-keywords))
+  ;;
+  (make-local-variable 'dna-valid-base-regexp)
+  (make-local-variable 'dna-sequence-start-regexp)
+  (make-local-variable 'dna-cruft-regexp)
+  (make-local-variable 'dna-isearch-case-fold-search)
+  ;;
+  (run-hooks 'dna-mode-hook))
+
+;; Keywords
+;; Todo: Seperate the keywords into a list for each format, rather
+;; than one for all.
+(defvar dna-font-lock-keywords
+  '(
+    ;; Fasta
+    ("^\\(>\\)\\([-_.|a-zA-Z0-9]+\\)\\([ \t]+.*\\)?"
+     (1 font-lock-keyword-face)
+     (2 font-lock-function-name-face)
+     (3 font-lock-comment-face nil t))
+
+    ;; Exp
+    ("^\\(ID\\) +\\([-_.a-zA-Z_0-9]+\\)"
+     (1 font-lock-keyword-face) (2 font-lock-function-name-face))
+    ("^\\(CC\\|SQ\\)\\([ \t]\\(.*\\)\\)?$"
+     (1 font-lock-keyword-face) (3 font-lock-comment-face nil t))
+    ("^\\(\\sw\\sw\\)[ \t]"
+     (1 font-lock-keyword-face))
+    ("^\\(//\\)"
+     (1 font-lock-keyword-face))
+
+    ;; Ace (phrap output)
+    ("^\\(DNA\\|Sequence\\|BaseQuality\\) +\\([-_.a-zA-Z_0-9]+\\)"
+     (1 font-lock-keyword-face) (2 font-lock-function-name-face))
+
+    ;; Genbank
+    ("^\\(LOCUS\\) +\\([-_.a-zA-Z_0-9]+\\)";; are '-_.' allowed?
+     (1 font-lock-keyword-face) (2 font-lock-function-name-face))
+    "ORIGIN"
+
+                                        ; More genbank keywords...
+    "ACCESSION" "AUTHORS" "AUTHORS" "BASE COUNT" "DEFINITION"
+    "FEATURES" "JOURNAL" "JOURNAL" "KEYWORDS" "MEDLINE" "NID"
+    "ORGANISM" "REFERENCE" "SEGMENT" "SOURCE" "TITLE"
+
+    ;; line numbers...
+    ("^[ \t]*\\([0-9]+\\)"
+     (1 font-lock-string-face))
+
+    ;; others...?
+    )
+  "Expressions to hilight in `dna-mode'.")
+
+
+;;; Setup functions
+(defun dna-find-file-func ()
+  "Invoke `dna-mode' if the buffer look like a sequence.
+and another mode is not active.
+This function is added to `find-file-hooks'."
+  (if (and (eq major-mode 'fundamental-mode)
+           (looking-at dna-sequence-start-regexp))
+    (dna-mode)))
+
+;;;###autoload
+(defun dna-add-hooks ()
+  "Add a default set of dna-hooks.
+These hooks will activate `dna-mode' when visiting a file
+which has a dna-like name (.fasta or .gb) or whose contents
+looks like dna.  It will also turn enable fontification for `dna-mode'."
+  (add-hook 'dna-mode-hook 'turn-on-font-lock)
+  (add-hook 'find-file-hooks 'dna-find-file-func)
+  (add-to-list
+   'auto-mode-alist
+   '("\\.\\(fasta\\|fa\\|exp\\|ace\\|gb\\)\\'" . dna-mode)))
+
+;; Setup hooks on request when this mode is loaded.
+(if dna-setup-on-load
+  (dna-add-hooks))
+
+(defun dna-next-char-func ()
+  "Should never be called.  Overridden in `dna-forward-base'."
+  (error "This shouldnt have been called"))
+
+;; Motion
+(defun dna-forward-base (count)
+  "Move forward COUNT bases.  Move backward if negative.
+Skip over dna-isearch-cruft.  Stop on non-base or
+non-whitespace characters."
+  (interactive "p")
+  (let ((c 0)
+        (abscount (abs count))
+        (dir (if (< count 0) -1 1))
+        dna-next-char-func
+        bstr)
+    ;; 
+    (fset 'dna-next-char-func (if (< dir 0) 'preceding-char 'following-char))
+    ;;
+    (while (< c abscount)
+      (setq bstr (char-to-string (dna-next-char-func)))
+      (cond
+       ((string-match dna-valid-base-regexp bstr)
+        (forward-char dir)
+        (setq c (1+ c)))
+       ((string-match dna-cruft-regexp bstr)
+        (forward-char dir))
+       (t
+        (message "Moved %d bases forward." c)
+        (setq abscount c))))            ; stop the while
+
+    ;; Move over trailing junk when moving forward
+    (if (= dir 1)
+      (while (string-match dna-cruft-regexp
+                           (char-to-string (dna-next-char-func)))
+        (forward-char dir))
+      )
+    ;; return the distance moved
+    (* dir abscount)))
+
+;; aaaaaaaaaa cccccccccc | gggggggggg tttttttttt
+
+(defun dna-backward-base (count)
+  "Move backward COUNT bases.  See `dna-forward-base'."
+  (interactive "p")
+  (dna-forward-base (- count)))
+
+(defun dna-beginning-of-sequence ()
+  "Move the start of the sequence or the buffer."
+  (interactive)
+  (goto-char
+   (or
+    (search-backward-regexp dna-sequence-start-regexp (point-min) t)
+    (point-min))))
+
+(defun dna-end-of-sequence ()
+  "Move to the end of the sequence or the buffer."
+  (interactive)
+  (end-of-line)
+  (skip-syntax-forward "-")
+  (let ((seqstart
+         (search-forward-regexp dna-sequence-start-regexp (point-max) t)))
+    (if seqstart (progn
+                   (goto-char seqstart)
+                   (beginning-of-line))
+        (goto-char (point-max)))))
+
+(defun dna-mark-sequence ()
+  "Put point at the beginning of a sequence, mark at end."
+  (interactive)
+  (dna-end-of-sequence)
+  (set-mark (point))
+  (dna-beginning-of-sequence))
+
+(defun dna-count-bases-region (d-start d-end)
+  "Count the number of bases in the region D-START to D-END.
+Echos the number of bases counted.
+If an invalid base is found, stops on the base and signals an error."
+  (interactive "r")
+  (let ((basecount 0))
+    (goto-char d-start)
+    (while (< (point) d-end)
+      (cond
+       ((looking-at dna-valid-base-regexp)
+        (setq basecount (1+ basecount))
+        (forward-char 1))
+       ((looking-at dna-cruft-regexp)
+        (forward-char 1))
+       (t
+        (error "Bad base found.  '%s'"
+               (buffer-substring (point) (1+ (point)))))
+       ))
+    (message "There are %d bases in the region." basecount)
+    basecount))
+
+;;; reverse and complement
+(defun dna-complement-base-list (base)
+  "Complement the BASE using a list based method.
+Returns the complement of the base.
+It can also be used to test if the character is a base,
+as all bases should have a complement."
+  (cdr (assq base dna-base-complement-list)))
+
+(defun dna-complement-base (base)
+  "Complement a BASE using a vector based method.
+See `dna-complement-base-list' for more info."
+  (aref dna-base-complement-vector base))
+
+(defun dna-complement (base)
+  "Look up the complement of the BASE and print a message.
+Handy for us CS types."
+  (interactive "cComplement of base:")
+  (message "Complement of '%c' is '%c'." base (dna-complement-base base)))
+
+(defun dna-complement-region (r-start r-end)
+  "Complement a region of bases from R-START to R-END.
+Complement a region of the buffer by deleting it and
+inserting the complements, base by base.  Non-bases are
+passed over unchanged."
+  (interactive "r")
+  (let (r-string r-length r-point r-base r-cbase)
+    (goto-char r-start)
+    (setq r-string (buffer-substring-no-properties r-start r-end))
+    (setq r-length (length r-string))
+    (delete-region r-start r-end)
+    (setq r-point 0)
+    (while (< r-point r-length)
+      (setq r-base (aref r-string r-point))
+      (setq r-cbase (dna-complement-base r-base))
+      (insert (if r-cbase r-cbase r-base))
+      (setq r-point (1+ r-point)))))
+
+;;;###autoload
+(defun dna-reverse-complement-region (r-start r-end)
+  "Reverse complement a region of dna from R-START to R-END.
+Works by deleting the region and inserting bases reversed
+and complemented, while entering non-bases in the order
+found."
+  (interactive "r")
+  (let (r-string r-length r-base r-cbase r-point r-mark)
+    (goto-char r-start)
+    (setq r-string (buffer-substring-no-properties r-start r-end))
+    (setq r-length (length r-string))
+    (setq r-mark (1- r-length))
+    (setq r-point 0)
+
+    ;; goodbye
+    (delete-region r-start r-end)
+
+    ;; insert the bases from back to front base by base
+    ;; insert non-bases from front to back to preserve spacing
+    (while (< r-point r-length)
+      (setq r-base (aref r-string r-point))
+      (setq r-cbase (dna-complement-base r-base))
+      (if r-cbase
+        (progn
+          ;; it is a base. find the reverse and complement it
+          (while (not (dna-complement-base (aref r-string r-mark)))
+            (setq r-mark (1- r-mark)))
+          (insert (dna-complement-base (aref r-string r-mark)))
+          (setq r-mark (1- r-mark)) )
+        ;; not a base, no change
+        (insert r-base))
+      (setq r-point (1+ r-point)))))
+
+;; format
+(defun dna-guess-format-func ()
+  "Guess the format of the sequence the point is at or after.
+Returns the format or nil."
+  (save-excursion
+    (end-of-line)
+    (dna-beginning-of-sequence)
+    (cond
+     ((looking-at "^>")   'fasta)
+     ((looking-at "^DNA") 'phrap)
+     ((looking-at "^ID")  'exp)
+     (t nil))))
+
+(defun dna-guess-format ()
+  "Guess and print the format of the sequence."
+  (interactive)
+  (message "%s" (dna-guess-format-func)))
+
+;;; dna-isearch stuff
+(defun dna-isearch-mangle-str (str)
+  "Mangle the string STR into a regexp to search over cruft in sequence.
+Inserts a regexp between each base which matches sequence formatting cruft.
+For example, if `dna-cruft-regexp' is            '[ ]',
+the search string 'acgt' would transformed into  'a[ ]*c[ ]*g[ ]*t[ ]*'"
+  (let ((i 0) (out ""))
+    (while (< i (length str))
+      (setq out (concat out (substring str i (1+ i)) dna-cruft-regexp "*"))
+      (setq i (1+ i)))
+    out))
+
+(defadvice isearch-message-prefix (around dna-isearch-ismp)
+  "Set the isearch prompt string to show dna search is active.
+This serves as a warning that the string is being mangled."
+  ad-do-it
+  (setq ad-return-value (concat "DNA " ad-return-value)))
+
+(defadvice isearch-search (around dna-isearch-iss)
+  "The advice used to mangle the search string in isearch."
+  (let ((isearch-regexp t)
+        ;; force case folding
+        (isearch-case-fold-search dna-isearch-case-fold-search)
+        (isearch-string (dna-isearch-mangle-str isearch-string)) )
+    ad-do-it))
+
+;;;###autoload
+(defun dna-isearch-forward ()
+  "Isearch forward on dna sequence.
+Enable the `dna-mode' search string mangling advice and start the search."
+  (interactive)
+  ;; Enable the prompt
+  (ad-enable-advice 'isearch-message-prefix 'around 'dna-isearch-ismp)
+  (ad-activate 'isearch-message-prefix)
+  ;; Enable the mangling
+  (ad-enable-advice 'isearch-search 'around 'dna-isearch-iss)
+  (ad-activate 'isearch-search)
+
+  ;; run the search
+  (isearch-forward)
+
+  ;;
+  (ad-disable-advice 'isearch-message-prefix 'around 'dna-isearch-ismp)
+  (ad-activate 'isearch-message-prefix)
+  ;; 
+  (ad-disable-advice 'isearch-search 'around 'dna-isearch-iss)
+  (ad-activate 'isearch-search))
+
+;;; Work with columns of sequences.
+
+(defun dna-column-select-func ()
+  "Return the start and end of the column as a cons.
+Point is moved forward one."
+  (let (s m e)
+    (setq m (point))
+    ;; work our way up
+    (while (looking-at dna-valid-base-regexp)
+      (setq s (point))
+      (previous-line 1))
+    (goto-char m)
+    ;; work our way down
+    (while (looking-at dna-valid-base-regexp)
+      (setq e (point))
+      (next-line 1))
+    (goto-char m)
+    ;; return the start and end of the column
+    (cons s (1+ e))))
+
+(defun dna-column-select ()
+  "Select the current column of text.
+Sets the mark at the top and the point at the bottom of a non-blank column."
+  (interactive)
+  (let ((se (dna-column-select-func)))
+    (goto-char (car se))
+    (push-mark)
+    (goto-char (cdr se))))
+
+(defvar dna-column-pad "*"
+  "Character to use when inserting a column of pads.")
+
+(defun dna-column-insert-pad ()
+  "Insert a column of pads."
+  (interactive)
+  (save-excursion
+    (let ((se (dna-column-select-func)))
+      (string-rectangle (car se) (cdr se) dna-column-pad))))
+
+(defun dna-column-delete ()
+  "Delete the current column of dna."
+  (interactive)
+  (save-excursion
+    (let ((se (dna-column-select-func)))
+      (kill-rectangle (car se) (cdr se)))))
+
+;;; Per base colors
+
+(defun dna-base-color-make-faces (&optional force)
+  "Build a face to display bases with.  FORCE remakes the faces."
+  (when (or (not (facep 'dna-face-t)) force)
+    (let ((base-list '("a" "c" "g" "t"))
+          base base-face)
+      (while base-list
+        (setq base (car base-list))
+        (setq base-face (intern (concat "dna-base-face-" base)))
+        (make-face base-face)
+        (set-face-foreground
+         base-face (symbol-value (intern (concat "dna-base-color-" base))))
+        (setq base-list (cdr base-list))))))
+
+;; Make faces on load
+(dna-base-color-make-faces t)
+
+(defvar dna-color-bases-auto t
+  "Automaticly deactivate `font-lock-mode' when `dna-color-bases' is run.
+See dna-color-bases for details.")
+;; (setq dna-color-bases-auto t)
+
+(defun dna-color-bases-region (s e)
+  "Color the bases in the region S to E.
+NOTE: The function `font-lock-mode' will undo the work of this
+function if activated.  Disable it before using this
+function.  If `dna-color-bases-auto' is set then `font-lock-mode'
+is deactivated automatically."
+  (interactive "r")
+  (if (and dna-color-bases-auto font-lock-mode)
+    (font-lock-mode -1))
+  (if font-lock-mode
+    (error "Font-lock-mode is on -- deactivate it"))
+  (save-excursion
+    (let (c)
+      (goto-char s)
+      (while (< s e)
+        (setq c (downcase (char-after s)))
+        (cond
+         ((eq c ?a)
+          (set-text-properties s (+ s 1) '(face dna-base-face-a)))
+         ((eq c ?c)             (+ s 1)
+          (set-text-properties s (+ s 1) '(face dna-base-face-c)))
+         ((eq c ?g)             (+ s 1)
+          (set-text-properties s (+ s 1) '(face dna-base-face-g)))
+         ((eq c ?t)             (+ s 1)
+          (set-text-properties s (+ s 1) '(face dna-base-face-t)))
+         (t nil))
+        (setq s (+ s 1))))))
+
+(defun dna-uncolor-bases-region (s e)
+  "Uncolor the bases from S to E."
+  (interactive "r")
+  (remove-text-properties s e '(face nil)))
+
+;;; Functions for me.
+
+;; I like to datestamp sequences I work with.
+(defvar dna-timestamp-format "%Y%m%d"
+  "Format of the time stamp which `dna-timestamp-seq' uses.")
+
+(defun dna-timestamp-seq ()
+  "Insert the current date into the sequence.
+Assumes fasta format."
+  (interactive)
+  (end-of-line)
+  (dna-beginning-of-sequence)
+  (end-of-line)
+  (insert "   " (format-time-string dna-timestamp-format (current-time))))
+
+;; done loading
+(run-hooks 'dna-mode-load-hook)
+(provide 'dna-mode)
+
+;;; dna-mode.el ends here
diff --git a/emacs_el/ecasound.el b/emacs_el/ecasound.el
new file mode 100644 (file)
index 0000000..895ee0c
--- /dev/null
@@ -0,0 +1,2321 @@
+;;; ecasound.el --- Interactive and programmatic interface to Ecasound
+
+;; Copyright (C) 2001, 2002  Mario Lang
+
+;; Author: Mario Lang <mlang@delysid.org>
+;; Keywords: audio, ecasound, eci, comint, process, pcomplete
+;; Version: 0.8.2
+
+;; This file 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 file is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; This file implements several aspects of ecasound use:
+;;
+;; * A derived-major-mode, from comint mode for an inferior ecasound
+;; process (ecasound-aim-mode).  Complete with context sensitive
+;; completion and interactive features to control the current process
+;; using ECI.
+;;
+;; * Ecasound Control Interface (ECI) library for programmatic control
+;; of a Ecasound process.  This allows you to write Ecasound batch
+;; jobs in Emacs-Lisp with Lisp functions and return values.  Have a
+;; look at eci-example and ecasound-normalize.
+;;
+;; * ecasound-ewf-mode, a mode for editing .ewf files.
+;;
+;;
+;; Usage:
+;;
+;; You need at least ecasound 2.2.0 for this file to work properly.
+;;
+;; Put ecasound.el in your load-path and require it in your .emacs.
+;; Set `ecasound-program' to the path to your ecasound executable.
+;;
+;;  (setq load-path (cons "/home/user/elisp")
+;;  (require 'ecasound)
+;;  (setq ecasound-program "/home/user/bin/ecasound"
+;;        eci-program "/home/user/bin/ecasound")
+;;
+;; To set ecasound startup options use
+;;
+;;  M-x ecasound-customize-startup RET
+;;
+;; Then use M-x ecasound RET to invoke an inferior ecasound process.
+;;
+;; For programmatic use of the ECI API, have a look at `eci-init',
+;; `eci-command' and in general the eci-* namespace.
+;;
+;; Compatibility:
+;;
+;; This file only works with GNU Emacs 21.  I've invested some minimal efforts
+;; to get it working with XEmacs, but have so far failed to succeed.
+;; Motivation isn't very high to get it working with XEmacs since I personally
+;; never use it.  So if you would like to use ecasound.el under XEmacs, you
+;; will have ttodo
+;;  M-x toggle-debug-on-error RET
+;; and see what you can figure out.  I'm happy to receive useful suggestions.
+;;
+;; Todo:
+;;
+;; * Find a better way to do status info fetching...
+;; * Add more conditions to the menu.
+;; * Use map-xxx-list data in the ecasound-copp widget.  This means we
+;;   need to merge cop-status and map-cop-list data somehow or have
+;;   the cop-editor fetch hints from map-cop/ladpsa/preset-list.
+;; * Make `ecasound-signalview' faster, and allow to invoke it on already
+;;   opened sessions.
+;; * Fix the case where ecasound sends output *after* the prompt.
+;;   This is tricky!  Fixed for internal parsing, probably will leave
+;;   like that for interactive use, not worth the trouble...
+;; * Copy documentation for ECI commands into eci-* docstrings and menu
+;;   :help keywords.
+;; * Expand the menu.
+;; * Bind most important interactive functions in ecasound-iam-mode-map
+;;   (which layout to use?)
+
+;;; History:
+;; 
+;; Version: 0.8.2
+;;
+;; * Added quite some missing docstrings.
+;; * New variable `ecasound-last-command-alist'.  Use that to do fancy stuff
+;;   to certain commands return values.
+;; * New variable `ecasound-type-alist'.  Normally you should not need to
+;;   change this, but it's nice to have it configurable.
+;; * New function `eci-is-valid-p'.  Rationale is that nil as return
+;;   value of a ECI command should indicate an error.  So this function
+;;   with a -p suffix to use as a predicate.
+;; * New variable `ecasound-parent' holds the parent buffer in a daemon buffer.
+;; * New variables ecasound-timer-flag&interval.
+;; * Renamed `eci-output-filter' to `ecasound-output-filter'.
+;; * New variable ecasound-mode|header-line-format.
+;; * `ecasound-cop-edit' now uses cop-set instead of
+;;   cop-select+copp-select+copp-set to update values.
+;; * Fixed multiple-argument handling.   They are separated with ',', not
+;;   with a space.
+;; * New variable ecasound-sending-command, used to prevent the background
+;;   timer from coliding with other ECI requests.
+;;
+;; Version: 0.8.1
+;;
+;; * Make ai|ao|cs-forward|rewind use ai|ao|cs-selected in the prompt
+;;   string of the interactive spec.
+;; * New keymaps ecasound-audioin|audioout-map.
+;;   Now you can be very quick:
+;;  M-x ecasound RET M-i a <select file> RET M-o d start RET
+;; * New menu ecasound-iam-ai|ao-menu.
+;; * defeci for ai|ao-add|forward|iselect|list|rewind|select|selected
+;; * Deleted `ecasound-buffer-name' and `eci-buffer-name' and replaced
+;;   calls to `make-comint-in-buffer' with `make-comint'.
+;; * Extended defeci's :cache and :cache-doc to defvar the variable.
+;; * Cleaned up some old alias definitions.
+;;
+;; Version: 0.8.0
+;;
+;; * New custom type ecasound-args, which is now used for `ecasound-arguments'
+;;   and `eci-arguments'.
+;; * If :cache is specified, also try to find a cached version in daemon-buffer
+;;   if available.
+;; * Added :alias keyword to defeci.  Delete defecialias.
+;; * Added ":pcomplete doc" to several defeci calls.
+;; * ecasound-cop|ctrl-add deleted and merged with the interactive spec of
+;;   eci-cop|ctrl-add.  Now if prefix arg (C-u) is given, prompt for plain
+;;   string, otherwise prompt with completion. Also changed binding
+;;   in ChainOp menu.
+;; * `ecasound-messages': variable deleted.
+;; * `ecasound-arguments': Now handles -d:nnn properly.
+;; * Many other minor tweaks and fixes.
+;;
+;; Version: 0.7.9
+;;
+;; * Cleanup and extend `defeci', now handles keyword :cache and :pcomplete.
+;;   Lots of `defeci'-caller updates, and additions.
+;; * Extended `ecasound-arguments' customize defition to handle --daemon,
+;; --daemon-port:nnn, -n:name and -b:size.  New interactive function
+;; `ecasound-customize-startup', also bound in "Ecasound menu."
+;; * Added status-information fetching via timer-function.  Puts
+;; info in mode-line as well as header-line. (warning, this feature is still
+;; a bit unstable.)
+;; * New macro `eci-hide-output' used to redirect action to `ecasound-daemon'
+;; if possible.  Several completion-fascilities updated to use it.
+;; * Various other fixes.
+;;
+;; Version: 0.7.8
+;;
+;; * Fix bug in "cop-add -el:" completion.
+;; * Made `ecasound-format-arg' a bit prettier.
+;; * Add --daemon support.  If --daemon is set in `ecasound-arguments',
+;; ecasound-iam-mode will take advantage of that and initialize a
+;; `ecasound-daemon' channel, as well as a periodic timer to update the
+;; mode-line.  M-: (display-buffer ecasound-daemon) RET to view its contents.
+;;
+;; Version: 0.7.7
+;;
+;; * Fixed hangup if a Stringlist ('S') returned a empty list.
+;; * Added keybindings.  See C-h m for details.  Still alot missing.
+;; * Added cs-forward and cs-rewind.  Can be used interactively, or
+;; prompt for value.  With no prefix arg, prompts for value, with
+;; prefix arg, uses that.  Example: C-u M-c M-s f forwards the chainsetup
+;; by 4 seconds, M-9 M-c M-s f forwards nine seconds ...
+;; * Fixed field-no-longer-editable bug when +/- is used in
+;; ecasound-cop-editor (thanks Per).  This also makes the slider useful again.
+;; * Got rid of ecasound-prompt assumptions in `eci-parse' and `eci-command'.
+;; * Make the eci-command family work with --daemon tcp/ip connections.
+;;   (no code for initialising daemon stuff yet, but eci-* commands
+;;    work fine with tcp/ip conns (tested manually).
+;; * `eci-parse' deleted and merged with `eci-output-filter'.
+;;
+;; Version: 0.7.6
+;;
+;; * Various minor bugfixes and enhancements.
+;; * Implemented ecasignalview as `ecasound-signalview' directly in Lisp.
+;; This is another demonstration that ECI was really a Good Thing(tm)!
+;; * Changed defeci to make it look more like a defun.
+;; * Removed eci-process-*-register handling completely. Rationale is
+;; that the map-*-list stuff is actually much more uniform and offers more
+;; info.
+;; * Rewrote `pcomplete/ecasound-iam-mode/cop-add' to use map-*-list.
+;; * Rewrote `ecasound-ctrl-add' using map-ctrl-list instead of ctrl-register
+;; and `ecasound-read-copp'.
+;; * Rewrote `ecasound-cop-add' using map-cop|ladspa|preset-list.
+;; * New function `eci-process-map-list' which processes the new map-xxx-list
+;; output into a wellformed Lisp list.
+;; * `ecasound-iam-commands' is now filled using int-cmd-list.
+;; * cop-map-list handling.  Used in `ecasound-cop-add' now.  New function
+;; `ecasound-read-copp' uses the now available default value.
+;;
+;; Version: 0.7.5
+;;
+;; * Added ctrl-register parsing support and `ecasound-ctrl-add'.
+;; * Added preset-register support (so far only for cop-add completion)
+;; * Fixed cop-status parsing bug which caused `ecasound-cop-edit' to not
+;; work in some cases.
+;; * New macro defeci which handles defining ECI commands in lisp.
+;; * Several other minor tweaks and fixes.
+;;
+;; Version: 0.7.4
+;;
+;; * Fixed `eci-command' once again, it blocked for nearly every call... :(
+;; * Fixed ecasound-cop-add in the ladspa case.
+;;
+;; Version: 0.7.3
+;;
+;; * Fixed missing require.
+;;
+;; Version: 0.7.2
+;;
+;; * Integrated ladspa-register into ecasound-cop-add
+;; Now we've a very huge list to select from using completion.
+;; * Some little cleanups.
+;; * Fixed ecasound-cop-add to actually add the ':' between name and args.
+;; * Removed the slider widget for now from the :format property of
+;; ecasound-copp.
+;; * Added `ecasound-messages' for a nice customisable interface to
+;; loglevels, strangely, cvs version doesnt seem to recognize
+;; -d:%d
+;;
+;; Version: 0.7.1
+;;
+;; * Created a slider widget.  It's not flawless, but it works!
+;;
+
+;;; Code:
+
+(require 'cl)
+(require 'comint)
+(require 'easymenu)
+(require 'pcomplete)
+(require 'widget)
+(require 'wid-edit)
+
+(defgroup ecasound nil
+  "Ecasound is a software package designed for multitrack audio processing.
+It can be used for simple tasks like audio playback, recording and format
+conversions, as well as for multitrack effect processing, mixing, recording
+and signal recycling.  Ecasound supports a wide range of audio inputs, outputs
+and effect algorithms.  Effects and audio objects can be combined in various
+ways, and their parameters can be controlled by operator objects like
+oscillators and MIDI-CCs.
+
+Variables in this group affect inferior ecasound processes started from
+within Emacs using the command `ecasound'.
+
+See the subgroup `eci' for settings which affect the programmatic interface
+to ECI."
+  :prefix "ecasound-"
+  :group 'processes)
+
+(define-widget 'ecasound-cli-arg 'string
+  "A Custom Widget for a command-line argument."
+  :format "%t: %v%d"
+  :string-match 'ecasound-cli-arg-string-match
+  :match 'ecasound-cli-arg-match
+  :value-to-internal
+  (lambda (widget value)
+    (when (widget-apply widget :string-match value)
+      (match-string 1 value)))
+  :value-to-external
+  (lambda (widget value)
+    (format (widget-apply widget :arg-format) value)))
+
+(defun ecasound-cli-arg-match (widget value)
+  (when (stringp value)
+    (widget-apply widget :string-match value)))
+
+(defun ecasound-cli-arg-string-match (widget value)
+  (string-match
+   (format (concat "^" (regexp-quote (widget-get widget :arg-format)))
+          (concat "\\(" (widget-get widget :pattern) "\\)"))
+   value))
+
+(define-widget 'ecasound-daemon-port 'ecasound-cli-arg
+  "A Custom Widget for the --daemon-port:port argument."
+  :pattern ".*"
+  :arg-format "--daemon-port:%s")
+
+(define-widget 'ecasound-chainsetup-name 'ecasound-cli-arg
+  "A Custom Widget for the -n:chainsetup argument."
+  :arg-format "-n:%s"
+  :doc "Sets the name of chainsetup.
+If not specified, defaults either to \"command-line-setup\" or to the file
+name from which chainsetup was loaded.  Whitespaces are not allowed."
+  :format "%t: %v%h"
+  :pattern ".*"
+  :tag "Chainsetup name")
+
+(define-widget 'ecasound-buffer-size 'ecasound-cli-arg
+  "A Custom Widget for the -b:buffer size argument."
+  :arg-format "-b:%s"
+  :doc "Sets the size of buffer in samples (must be an exponent of 2).
+This is quite an important option. For real-time processing, you should set
+this as low as possible to reduce the processing delay.  Some machines can
+handle buffer values as low as 64 and 128.  In some circumstances (for
+instance when using oscillator envelopes) small buffer sizes will make
+envelopes act more smoothly.  When not processing in real-time (all inputs
+and outputs are normal files), values between 512 - 4096 often give better
+results."
+  :format "%t: %v%h"
+  :pattern "[0-9]+"
+  :tag "Buffer size")
+
+(define-widget 'ecasound-debug-level 'set
+  "Custom widget for the -d:nnn argument."
+  :arg-format "-d:%s"
+  :args '((const :tag "Errors" 1)
+         (const :tag "Info" 2)
+         (const :tag "Subsystems" 4)
+         (const :tag "Module names" 8)
+         (const :tag "User objects" 16)
+         (const :tag "System objects" 32)
+         (const :tag "Functions" 64)
+         (const :tag "Continuous" 128)
+         (const :tag "EIAM return values" 256))
+  :doc "Set the debug level"
+  :match 'ecasound-cli-arg-match
+  :pattern "[0-9]+"
+  :string-match 'ecasound-cli-arg-string-match
+  :tag "Debug level"
+  :value-to-external
+  (lambda (widget value)
+    (format (widget-get widget :arg-format)
+           (number-to-string (apply #'+ (widget-apply widget :value-get)))))
+  :value-to-internal
+  (lambda (widget value)
+    (when (widget-apply widget :string-match value)
+      (let ((level (string-to-number (match-string 1 value)))
+           (levels (nreverse
+                    (mapcar (lambda (elt) (car (last elt)))
+                            (widget-get widget :args)))))
+       (if (or (> level (apply #'+ levels)) (< level 0))
+           (error "Invalid debug level %d" level)
+         (delq nil
+               (mapcar (lambda (elem)
+                         (when (eq (/ level elem) 1)
+                           (setq level (- level elem))
+                           elem)) levels)))))))
+(define-widget 'ecasound-args 'set
+  ""
+  :args '((const :tag "Start ecasound in interactive mode" "-c")
+         (const :tag "Print all debug information to stderr"
+                :doc "(unbuffered, plain output without ncurses)"
+                "-D")
+         (ecasound-debug-level)
+         (list :format "%v" :inline t
+               (const :tag "Allow remote connections:" "--daemon")
+               (ecasound-daemon-port :tag "Daemon port" "--daemon-port:2868"))
+         (ecasound-buffer-size "-b:1024")
+         (ecasound-chainsetup-name "-n:eca-el-setup")
+         (const :tag "Truncate outputs" :format "%t\n%h"
+                    :doc "All output objects are opened in overwrite mode.
+Any existing files will be truncated."
+                    "-x")
+             (const :tag "Open outputs for updating"
+                    :doc "Ecasound opens all outputs - if target format allows it - in readwrite mode."
+                    "-X")
+             (repeat :tag "Others" :inline t (string :tag "Argument"))))
+
+(defcustom ecasound-arguments '("-c" "-d:259" "--daemon" "--daemon-port:2868"
+                               "-n:eca-el-setup")
+  "*Command line arguments used when starting an ecasound process."
+  :group 'ecasound
+  :type 'ecasound-args)
+
+(defun ecasound-daemon-port ()
+  "Return the port number defined in `ecasound-arguments'."
+  (let ((elem (member* "^--daemon-port:\\(.*\\)" ecasound-arguments
+                      :test #'string-match)))
+    (if elem
+       (match-string 1 (car elem)))))
+
+(defun ecasound-customize-startup ()
+  "Customize ecasound startup arguments."
+  (interactive)
+  (customize-variable 'ecasound-arguments))
+
+(defcustom ecasound-program "/home/mlang/bin/ecasound"
+  "*Ecasound's executable.
+This program is executed when the user invokes \\[ecasound]."
+  :group 'ecasound
+  :type 'file)
+
+(defcustom ecasound-prompt-regexp "^ecasound[^>]*> "
+  "Regexp to use to match the prompt."
+  :group 'ecasound
+  :type 'regexp)
+
+(defcustom ecasound-parse-cleanup-buffer t
+  "*Indicates if `ecasound-output-filter' should cleanup the buffer.
+This means the loglevel, msgsize and return type will get removed if
+parsed successfully."
+  :group 'ecasound
+  :type 'boolean)
+
+(defcustom ecasound-error-hook nil
+  "*Called whenever a ECI error happens."
+  :group 'ecasound
+  :type 'hook)
+
+(defcustom ecasound-message-hook '(ecasound-print-message)
+  "*Hook called whenever a message except loglevel 256 (eci) is received.
+Arguments are LOGLEVEL and STRING."
+  :group 'ecasound
+  :type 'hook)
+
+(defun ecasound-print-message (level msg)
+  "Simple function which prints every message regardless which loglevel.
+Argument LEVEL is the debug level."
+  (message "Ecasound (%d): %s" level msg))
+
+(defface ecasound-error-face '((t (:foreground "White" :background "Red")))
+  "Face used to highlight errors."
+  :group 'ecasound)
+
+(defcustom ecasound-timer-flag t
+  "*If non-nil, fetch status information in background."
+  :group 'ecasound
+  :type 'boolean)
+
+(defcustom ecasound-timer-interval 2
+  "*Defines how often status information should be fetched."
+  :group 'ecasound
+  :type 'number)
+
+(defcustom ecasound-mode-line-format
+  '("-"
+    mode-line-frame-identification
+    mode-line-buffer-identification
+    eci-engine-status " "
+    ecasound-mode-string
+    " %[("
+    (:eval (mode-line-mode-name))
+    mode-line-process
+    minor-mode-alist
+    "%n"
+    ")%]--"
+   (line-number-mode "L%l--")
+   (column-number-mode "C%c--")
+   (-3 . "%p")
+   "-%-")
+  "*Mode Line Format used in `ecasound-iam-mode'."
+  :group 'ecasound
+  :type '(repeat
+         (choice
+          string
+          variable
+          (cons integer string)
+          (list :tag "Evaluate" (const :value :eval) sexp)
+          (repeat sexp))))
+
+(defcustom ecasound-header-line-format nil
+  "*If non-nil, defines the header line format for `ecasound-iam-mode' buffers."
+  :group 'ecasound
+  :type 'sexp)
+
+(defvar ecasound-sending-command nil
+  "Non-nil if `eci-command' is running.")
+
+(make-variable-buffer-local
+ (defvar ecasound-daemon nil
+   "If non-nil, this variable holds the buffer object of a daemon channel."))
+
+(make-variable-buffer-local
+ (defvar ecasound-parent nil
+   "If non-nil, this variable holds the buffer object of a daemon parent."))
+
+(make-variable-buffer-local
+ (defvar ecasound-daemon-timer nil))
+
+(defvar ecasound-chain-map nil
+  "Keymap used for Chain operations.")
+(define-prefix-command 'ecasound-chain-map)
+(define-key 'ecasound-chain-map "a" 'eci-c-add)
+(define-key 'ecasound-chain-map "c" 'eci-c-clear)
+(define-key 'ecasound-chain-map "d" 'eci-c-deselect)
+(define-key 'ecasound-chain-map "m" 'eci-c-mute)
+(define-key 'ecasound-chain-map "x" 'eci-c-remove)
+(define-key 'ecasound-chain-map (kbd "M-s") 'ecasound-cs-map)
+(define-key 'ecasound-chain-map (kbd "M-o") 'ecasound-cop-map)
+(defvar ecasound-cop-map nil
+  "Keymap used for Chain operator operations.")
+(define-prefix-command 'ecasound-cop-map)
+(define-key 'ecasound-cop-map "a" 'eci-cop-add)
+(define-key 'ecasound-cop-map "i" 'eci-cop-select)
+(define-key 'ecasound-cop-map "l" 'eci-cop-list)
+(define-key 'ecasound-cop-map "s" 'eci-cop-status)
+(define-key 'ecasound-cop-map "x" 'eci-cop-remove)
+(defvar ecasound-audioin-map nil
+  "Keymap used for audio input objects.")
+(define-prefix-command 'ecasound-audioin-map)
+(define-key 'ecasound-audioin-map "a" 'eci-ai-add)
+(define-key 'ecasound-audioin-map "f" 'eci-ai-forward)
+(define-key 'ecasound-audioin-map "r" 'eci-ai-rewind)
+(define-key 'ecasound-audioin-map "x" 'eci-ai-remove)
+(defvar ecasound-audioout-map nil
+  "Keymap used for audio output objects.")
+(define-prefix-command 'ecasound-audioout-map)
+(define-key 'ecasound-audioout-map "a" 'eci-ao-add)
+(define-key 'ecasound-audioout-map "d" 'eci-ao-add-default)
+(define-key 'ecasound-audioout-map "f" 'eci-ao-forward)
+(define-key 'ecasound-audioout-map "r" 'eci-ao-rewind)
+(define-key 'ecasound-audioout-map "x" 'eci-ao-remove)
+(defvar ecasound-cs-map nil
+  "Keymap used for Chainsetup operations.")
+(define-prefix-command 'ecasound-cs-map)
+(define-key 'ecasound-cs-map "a" 'eci-cs-add)
+(define-key 'ecasound-cs-map "c" 'eci-cs-connect)
+(define-key 'ecasound-cs-map "d" 'eci-cs-disconnect)
+(define-key 'ecasound-cs-map "f" 'eci-cs-forward)
+(define-key 'ecasound-cs-map "r" 'eci-cs-rewind)
+(define-key 'ecasound-cs-map "t" 'eci-cs-toogle-loop)
+
+(defvar ecasound-iam-mode-map
+  (let ((map (make-sparse-keymap)))
+    (set-keymap-parent map comint-mode-map)
+    (define-key map "\t" 'pcomplete)
+    (define-key map (kbd "M-c") 'ecasound-chain-map)
+    (define-key map (kbd "M-i") 'ecasound-audioin-map)
+    (define-key map (kbd "M-o") 'ecasound-audioout-map)
+    (define-key map (kbd "M-\"") 'eci-command)
+    map))
+
+(easy-menu-define
+  ecasound-iam-cs-menu ecasound-iam-mode-map
+  "Chainsetup menu."
+  (list "Chainsetup"
+       ["Add..." eci-cs-add t]
+       ["Load..." eci-cs-load t]
+       ["Save" eci-cs-save t]
+       ["Save As..." eci-cs-save-as t]
+       ["List" eci-cs-list t]
+       ["Select" eci-cs-select t]
+       ["Select via index" eci-cs-index-select t]
+       "-"
+       ["Selected" eci-cs-selected t]
+       ["Valid?" eci-cs-is-valid t]
+       ["Connect" eci-cs-connect (eci-cs-is-valid-p)]
+       ["Disconnect" eci-cs-disconnect t]
+       ["Get position" eci-cs-get-position t]
+       ["Get length" eci-cs-get-length t]
+       ["Get length in samples" eci-cs-get-length-samples t]
+       ["Forward..." eci-cs-forward t]
+       ["Rewind..." eci-cs-rewind t]
+       ))
+(easy-menu-add ecasound-iam-cs-menu ecasound-iam-mode-map)
+(easy-menu-define
+  ecasound-iam-c-menu ecasound-iam-mode-map
+  "Chain menu."
+  (list "Chain"
+       ["Add..." eci-c-add t]
+       ["Select..." eci-c-select t]
+       ["Select All" eci-c-select-all t]
+       ["Deselect..." eci-c-deselect (> (length (eci-c-selected)) 0)]
+       ["Selected" eci-c-selected t]
+       ["Mute" eci-c-mute t]
+       ["Clear" eci-c-clear t]
+       ))
+(easy-menu-add ecasound-iam-c-menu ecasound-iam-mode-map)
+(easy-menu-define
+  ecasound-iam-cop-menu ecasound-iam-mode-map
+  "Chain Operator menu."
+  (list "ChainOp"
+       ["Add..." eci-cop-add (> (length (eci-c-selected)) 0)]
+       ["Select..." eci-cop-select t]
+       ["Edit..." ecasound-cop-edit t]
+       "-"
+       ["Select parameter..." eci-copp-select t]
+       ["Get parameter value" eci-copp-get t]
+       ["Set parameter value..." eci-copp-set t]
+       ))
+(easy-menu-add ecasound-iam-c-menu ecasound-iam-mode-map)
+(easy-menu-define
+  ecasound-iam-ai-menu ecasound-iam-mode-map
+  "Audio Input Object menu."
+  (list "AudioIn"
+       ["Add..." eci-ai-add (> (length (eci-c-selected)) 0)]
+       ["List" eci-ai-list t]
+       ["Select..." eci-ai-select t]
+       ["Index select..." eci-ai-index-select t]
+       "-"
+       ["Attach" eci-ai-attach t]
+       ["Remove" eci-ai-remove t]
+       ["Forward..." eci-ai-forward t]
+       ["Rewind..." eci-ai-rewind t]
+       ))
+(easy-menu-add ecasound-iam-ai-menu ecasound-iam-mode-map)
+(easy-menu-define
+  ecasound-iam-ao-menu ecasound-iam-mode-map
+  "Audio Output Object menu."
+  (list "AudioOut"
+       ["Add..." eci-ao-add (> (length (eci-c-selected)) 0)]
+       ["Add default" eci-ao-add-default (> (length (eci-c-selected)) 0)]
+       ["List" eci-ao-list t]
+       ["Select..." eci-ao-select t]
+       ["Index select..." eci-ao-index-select t]
+       "-"
+       ["Attach" eci-ao-attach t]
+       ["Remove" eci-ao-remove t]
+       ["Forward..." eci-ao-forward t]
+       ["Rewind..." eci-ao-rewind t]
+       ))
+(easy-menu-add ecasound-iam-ao-menu ecasound-iam-mode-map)
+
+(easy-menu-define
+  ecasound-menu global-map
+  "Ecasound menu."
+  (list "Ecasound"
+       ["Get session" ecasound t]
+       "-"
+       ["Normalize..." ecasound-normalize t]
+       ["Signalview..." ecasound-signalview t]
+       "-"
+       ["Customize startup..." ecasound-customize-startup t]
+       ))
+(easy-menu-add ecasound-menu global-map)
+
+(make-variable-buffer-local
+ (defvar ecasound-mode-string nil))
+
+(define-derived-mode ecasound-iam-mode comint-mode "EIAM"
+  "Special mode for ecasound processes in interactive mode."
+  (set (make-local-variable 'comint-prompt-regexp)
+       (set (make-local-variable 'paragraph-start)
+           ecasound-prompt-regexp))
+  (add-hook 'comint-output-filter-functions 'ecasound-output-filter nil t)
+  (add-hook 'comint-input-filter-functions 'eci-input-filter nil t)
+  (ecasound-iam-setup-pcomplete)
+  (setq mode-line-format ecasound-mode-line-format))
+
+(defun ecasound-mode-line-cop-list (handle)
+  (let ((list (eci-cop-list handle))
+       (sel (1- (eci-cop-selected handle)))
+       (str ""))
+    (dotimes (i (length list) str)
+      (setq str (format "%s%s%s%s"
+                       str
+                       (if (= i sel) "*" "")
+                       (nth i list)
+                       (if (= i (length list)) "" ","))))))
+
+(defsubst ecasound-daemon-p ()
+  "Predicate used to determine if there is an active daemon channel."
+  (and (buffer-live-p ecasound-daemon)
+       (eq (process-status ecasound-daemon) 'open)))
+
+(defun ecasound-kill-timer ()
+  "Cancels the background timer.
+Use this if you want to stop background information fetching."
+  (interactive)
+  (when ecasound-daemon-timer
+    (cancel-timer ecasound-daemon-timer)))
+
+(defun ecasound-kill-daemon ()
+  "Terminate the daemon channel."
+  (interactive)
+  (ecasound-kill-timer)
+  (when (ecasound-daemon-p)
+    (kill-buffer ecasound-daemon)))
+
+(defun ecasound-update-mode-line (buffer)
+  (when (and (buffer-live-p buffer)
+            (get-buffer-window buffer 'visible))
+    (unless ecasound-sending-command
+      (with-current-buffer buffer
+       (when (ecasound-daemon-p)
+         (eci-engine-status ecasound-daemon)
+         (setq ecasound-mode-string
+               (list
+                " [" (ecasound-position-to-string
+                      (eci-cs-get-position ecasound-daemon))
+                "/" (ecasound-position-to-string
+                     (eci-cs-get-length ecasound-daemon))
+                "]"
+                )
+               header-line-format
+               (list
+                (eci-cs-selected ecasound-daemon)
+                " [" (if (eci-cs-is-valid-p ecasound-daemon)
+                         "valid"
+                       "N/A") "]: ("
+                (mapconcat 'identity (eci-c-list ecasound-daemon) ",")
+                ") "
+                (mapconcat 'identity
+                           (eci-c-selected ecasound-daemon) ","))))))))
+
+(defun ecasound-setup-timer ()
+  (when (and ecasound-timer-flag (ecasound-daemon-p))
+    (setq ecasound-daemon-timer
+         (run-with-timer
+          0 ecasound-timer-interval
+          'ecasound-update-mode-line
+          (current-buffer)))))
+
+(make-variable-buffer-local
+ (defvar eci-int-output-mode-wellformed-flag nil
+   "Indicates if int-output-mode-wellformed was successfully initialized."))
+
+(make-variable-buffer-local
+ (defvar eci-engine-status nil
+   "If non-nil, a string describing the engine-status."))
+
+(make-variable-buffer-local
+ (defvar eci-cs-selected nil
+   "If non-nil, a string describing the selected chain setup."))
+
+;;;###autoload
+(defun ecasound (&optional buffer)
+  "Run an inferior ecasound, with I/O through BUFFER.
+BUFFER defaults to `*ecasound*'.
+Interactively, a prefix arg means to prompt for BUFFER.
+If BUFFER exists but ecasound process is not running, make new ecasound
+process using `ecasound-arguments'.
+If BUFFER exists and ecasound process is running, just switch to BUFFER.
+The buffer is put in ecasound mode, giving commands for sending input and
+completing IAM commands.  See `ecasound-iam-mode'.
+
+\(Type \\[describe-mode] in the ecasound buffer for a list of commands.)"
+  (interactive
+   (list
+    (and current-prefix-arg
+        (read-buffer "Ecasound buffer: " "*ecasound*"))))
+  (when (null buffer)
+    (setq buffer "*ecasound*"))
+  (if (not (comint-check-proc buffer))
+      (pop-to-buffer
+       (save-excursion
+        (set-buffer
+         (apply 'make-comint
+                "ecasound"
+                ecasound-program
+                nil
+                ecasound-arguments))
+        (ecasound-iam-mode)
+        ;; Flush process output
+        (while (accept-process-output
+                (get-buffer-process (current-buffer))
+                1))
+        (if (consp ecasound-program)
+            ;; If we're connecting via tcp/ip, we're most probably connecting
+            ;; to a daemon-mode ecasound session.
+            (setq comint-input-sender 'ecasound-network-send
+                  eci-int-output-mode-wellformed-flag t)
+          (let ((eci-hide-output nil))
+            (if (not (eq (eci-command "int-output-mode-wellformed") t))
+                (message "Failed to initialize properly"))))
+        (when (member "--daemon" ecasound-arguments)
+          (ecasound-setup-daemon))
+        (current-buffer)))
+    (pop-to-buffer buffer)))
+
+(defun ecasound-setup-daemon ()
+  (let ((cb (current-buffer)))
+    (if (ecasound-daemon-p)
+       (error "Ecasound Daemon %S already initialized" ecasound-daemon)
+      (setq ecasound-daemon
+           (save-excursion
+             (set-buffer
+              (make-comint
+               "ecasound-daemon"
+               (cons "localhost" (ecasound-daemon-port))))
+             (ecasound-iam-mode)
+             (setq comint-input-sender 'ecasound-network-send
+                   eci-int-output-mode-wellformed-flag t
+                   ecasound-parent cb)
+             (set (make-variable-buffer-local 'comint-highlight-prompt) nil)
+             (setq comint-output-filter-functions '(ecasound-output-filter))
+             (current-buffer)))
+      (if (ecasound-daemon-p)
+         (progn (add-hook 'kill-buffer 'ecasound-kill-daemon nil t)
+                (ecasound-setup-timer))
+       (message "Ecasound daemon initialisation failed")))))
+
+(defun ecasound-delete-last-in-and-output ()
+  "Delete the region of text generated by the last in and output.
+This is usually used to hide ECI requests from the user."
+  (delete-region
+   (save-excursion (goto-char comint-last-input-end) (forward-line -1)
+                  (unless (looking-at ecasound-prompt-regexp)
+                    (error "Assumed ecasound-prompt"))
+                  (point))
+   comint-last-output-start))
+
+(make-variable-buffer-local
+ (defvar eci-last-command nil
+   "Last command sent to the ecasound process."))
+
+(make-variable-buffer-local
+ (defvar ecasound-last-parse-start nil
+   "Where to start parsing if output is received.
+This marker is advanced everytime a successful parse happens."))
+
+(defun eci-input-filter (string)
+  "Track commands sent to ecasound.
+Argument STRING is the input sent."
+  (when (string-match "^[[:space:]]*\\([a-zA-Z-]+\\)[\n\t ]+" string)
+    (setq eci-last-command (match-string-no-properties 1 string)
+         ;; This is a precaution, but it makes sense
+         ecasound-last-parse-start (point))
+    (when (or (string= eci-last-command "quit")
+             (string= eci-last-command "q"))
+      ;; Prevents complete hangup, still a bit mysterius
+      (ecasound-kill-daemon))))
+
+(defun ecasound-network-send (proc string)
+  "Function for sending to PROC input STRING via network."
+  (comint-send-string proc string)
+  (comint-send-string proc "\r\n"))
+
+(defcustom ecasound-last-command-alist
+  '(("int-output-mode-wellformed" .
+     (setq eci-int-output-mode-wellformed-flag t))
+    ("int-cmd-list" .
+     (setq ecasound-iam-commands value))
+    ("map-cop-list" .
+     (setq eci-map-cop-list (eci-process-map-list value)))
+    ("map-ladspa-list" .
+     (setq eci-map-ladspa-list (eci-process-map-list value)))
+    ("map-ctrl-list" .
+     (setq eci-map-ctrl-list (eci-process-map-list value)))
+    ("map-preset-list" .
+     (setq eci-map-preset-list (eci-process-map-list value)))
+    ("cop-status" .
+     (eci-process-cop-status value))
+    ("engine-status" .
+     (setq eci-engine-status value))
+    ("cs-selected" .
+     (setq eci-cs-selected value)))
+  "*Alist of command/expression pairs.
+If `ecasound-last-command' is one of the alist keys, the value of that entry
+will be evaluated with the variable VALUE bound to the commands
+result value."
+  :group 'ecasound
+  :type '(alist :key-type (string :tag "Command")
+               :value-type (sexp :tag "Lisp Expression")))
+               
+(defcustom ecasound-type-alist
+  '(("-"  . t)
+    ("i"  . (string-to-number value))
+    ("li" . (string-to-number value))
+    ("f"  . (string-to-number value))
+    ("s"  . value)
+    ("S"  . (split-string value ","))
+    ("e"  . (progn (run-hook-with-args 'ecasound-error-hook value) nil)))
+  "*Alist defining ECI type conversion.
+Each key is a type, and the values are Lisp expressions.  During evaluation
+the variables TYPE and VALUE are bound respectively."
+  :group 'ecasound
+  :type '(alist :key-type (string :tag "Type")
+               :value-type (sexp :tag "Lisp Expression")))
+
+(defun ecasound-process-result (type value)
+  "Process ecasound result.
+This function is called if `ecasound-output-filter' detected an ECI reply.
+Argument TYPE the ECI type as a string and argument VALUE is the value as
+a string.
+This function uses `ecasound-type-alist' and `ecasound-last-command-alist'
+to decide how to transform its arguments."
+  (let ((tcode (member* type ecasound-type-alist :test 'string= :key 'car))
+       (lcode (member* eci-last-command ecasound-last-command-alist
+                       :test 'string= :key 'car)))
+    (if tcode
+       (setq value (eval (cdar tcode)))
+      (error "Return type '%s' not defined in `ecasound-type-alist'" type))
+    (setq eci-return-value value
+         eci-return-type type
+         eci-result
+         (if lcode
+             (eval (cdar lcode))
+           value))))
+
+(make-variable-buffer-local
+ (defvar eci-return-type nil
+   "The return type of the last received return value as a string."))
+
+(make-variable-buffer-local
+ (defvar eci-return-value nil
+   "The last received return value as a string."))
+
+(make-variable-buffer-local
+ (defvar eci-result nil
+   "The last received return value as a Lisp Object."))
+
+(defun ecasound-output-filter (string)
+  "Parse ecasound process output.
+This function should be used on `comint-output-filter-functions' hook.
+STRING is the string originally received and inserted into the buffer."
+  (let ((start (or ecasound-last-parse-start (point-min)))
+       (end (process-mark (get-buffer-process (current-buffer)))))
+    (when (< start end)
+      (save-excursion
+       (let (type value (end (copy-marker end)))
+         (goto-char start)
+         (while (re-search-forward
+                 "\\([0-9]\\{1,3\\}\\) \\([0-9]\\{1,5\\}\\)\\( \\(.*\\)\\)?\n"
+                 end t)
+           (let* ((loglevel (string-to-number (match-string 1)))
+                  (msgsize (string-to-number (match-string 2)))
+                  (return-type (match-string-no-properties 4))
+                  (msg (buffer-substring-no-properties
+                        (point)
+                        (progn
+                          (if (> (- (point-max) (point)) msgsize)
+                            (progn
+                              (forward-char msgsize)
+                              (if (not (save-match-data
+                                         (looking-at
+                                          "\\(\n\n\\|\r\n\r\n\\)")))
+                                  (error "Malformed ECI message")
+                                (point)))
+                            (point-max))))))
+             (when (= msgsize (length msg))
+               (if (and (= loglevel 256)
+                        (string= return-type "e"))
+                   (add-text-properties
+                    (match-end 0) (point)
+                    (list 'face 'ecasound-error-face)))
+               (when ecasound-parse-cleanup-buffer
+                 (delete-region (match-beginning 0) (if (= msgsize 0)
+                                                        (point)
+                                                      (match-end 0)))
+                 (delete-char 1))
+               (setq ecasound-last-parse-start (point))
+               (if (not (= loglevel 256))
+                   (run-hook-with-args 'ecasound-message-hook loglevel msg)
+                 (setq value msg
+                       type (if (string-match "\\(.*\\)\r" return-type)
+                                (match-string 1 return-type)
+                              return-type))))))
+         (when type
+           (ecasound-process-result type value)))))))
+
+(defmacro defeci (name &optional args doc &rest body)
+  "Defines an ECI command.
+Argument NAME is used for the function name with eci- as prefix.
+Optional argument ARGS specifies the arguments this ECI command has.
+Optional argument DOC is the docstring used for the defined function.
+BODY can start with keyword arguments to indicated certain special cases.  The
+following keyword arguments are implemented:
+ :cache VARNAME  The command should try to find a cached version of the result
+                 in VARNAME.
+ :pcomplete VALUE The command can provide programmable completion.  Possible
+                  values are the symbol DOC, which indicates that pcomplete
+                  should echo the docstring of the eci command.  Alternatively
+                  you can provide a sexp which is used for the pcomplete
+                  definition."
+  (let ((sym (intern (format "eci-%S" name)))
+       (pcmpl-sym (intern (format "pcomplete/ecasound-iam-mode/%S" name)))
+       (cmd `(eci-command
+              ,(if args
+                   `(format ,(format "%S %s"
+                                     name (mapconcat #'caddr args ","))
+                            ,@(mapcar
+                               (lambda (arg)
+                                 `(if (or (stringp ,(car arg))
+                                          (numberp ,(car arg)))
+                                      ,(car arg)
+                                    (mapconcat #'identity ,(car arg) ",")))
+                               args))
+                 (format "%S" name))
+              buffer-or-process))
+       cache cache-doc pcmpl aliases)
+    (while (keywordp (car body))
+      (case (pop body)
+       (:cache (setq cache (pop body)))
+       (:cache-doc (setq cache-doc (pop body)))
+       (:pcomplete (setq pcmpl (pop body)))
+       (:alias (setq aliases (pop body)))
+       (t (pop body))))
+    (when (and (not (eq aliases nil))
+              (not (consp aliases)))
+      (setq aliases (list aliases)))
+    `(progn
+     ,(if cache
+         `(make-variable-buffer-local
+           (defvar ,cache ,@(if cache-doc (list nil cache-doc) (list nil)))))
+     (defun ,sym
+       ,(if args (append (mapcar #'car args) `(&optional buffer-or-process))
+         `(&optional buffer-or-process))
+       ,(if doc doc "")
+       ,(if args `(interactive
+                  ,(if (let (done)
+                         (mapcar (lambda (x) (when x (setq done t)))
+                                 (mapcar #'stringp (mapcar #'cadr args)))
+                         done)
+                       (mapconcat #'identity (mapcar #'cadr args) "\n")
+                     `(list ,@(mapcar #'cadr args))))
+         `(interactive))
+       ,@(cond
+         ((and cache (eq body nil))
+          `((let ((cached (with-current-buffer
+                              (ecasound-find-buffer buffer-or-process)
+                            ,(or cache (and (ecasound-daemon-p)
+                                            (with-current-buffer
+                                                ecasound-daemon
+                                              ,cache))))))
+              (if cached
+                  cached
+                ,cmd))))
+         ((eq body nil)
+          `(,cmd))
+         (t body)))
+     ,@(mapcar
+       (lambda (alias) `(defalias ',(intern (format "eci-%S" alias))
+                          ',sym)) aliases)
+     ,(when pcmpl
+       `(progn
+          ,(if (and (eq pcmpl 'doc) (stringp doc) (not (string= doc "")))
+               `(defun ,pcmpl-sym ()
+                  (message ,doc)
+                  (throw 'pcompleted t))
+             `(defun ,pcmpl-sym ()
+                ,pcmpl))
+          ,@(mapcar
+             (lambda (alias)
+               `(defalias ',(intern (format "pcomplete/ecasound-iam-mode/%S" alias))
+                  ',pcmpl-sym))
+             aliases))))))
+
+(defeci map-cop-list ()
+  "Returns a list of registered chain operators."
+  :cache eci-map-cop-list
+  :cache-doc "If non-nil, contains the chainop object map.
+It has the form
+ ((NAME PREFIX DESCR ((ARGNAME DESCR DEFAULT LOW HIGH TYPE) ...)) ...)
+
+Use `eci-map-cop-list' to fill this variable with data.")
+
+(defeci map-ctrl-list ()
+  "Returns a list of registered controllers."
+  :cache eci-map-ctrl-list
+  :cache-doc "If non-nil, contains the chainop controller object map.
+It has the form
+ ((NAME PREFIX DESCR ((ARGNAME DESCR DEFAULT LOW HIGH TYPE) ...)) ...)
+
+Use `eci-map-ctrl-list' to fill this list with data.")
+
+(defeci map-ladspa-list ()
+  "Returns a list of registered LADSPA plugins."
+  :cache eci-map-ladspa-list
+  :cache-doc "If non-nil, contains the LADSPA object map.
+It has the form
+ ((NAME PREFIX DESCR ((ARGNAME DESCR DEFAULT LOW HIGH TYPE) ...)) ...)
+
+Use `eci-map-ladspa-list' to fill this list with data.")
+
+(defeci map-preset-list ()
+  "Returns a list of registered effect presets."
+  :cache eci-map-preset-list
+  :cache-doc "If non-nil, contains the preset object map.
+It has the form
+ ((NAME PREFIX DESCR ((ARGNAME DESCR DEFAULT LOW HIGH TYPE) ...)) ...)
+
+Use `eci-map-preset-list' to fill this list with data.")
+
+;;; Ecasound-iam-mode pcomplete functions
+
+(defun ecasound-iam-setup-pcomplete ()
+  "Setup buffer-local functions for pcomplete in `ecasound-iam-mode'."
+  (set (make-local-variable 'pcomplete-command-completion-function)
+       (lambda ()
+        (pcomplete-here (if ecasound-iam-commands
+                            ecasound-iam-commands
+                          (eci-hide-output eci-int-cmd-list)))))
+  (set (make-local-variable 'pcomplete-command-name-function)
+       (lambda ()
+         (pcomplete-arg 'first)))
+  (set (make-local-variable 'pcomplete-parse-arguments-function)
+       'ecasound-iam-pcomplete-parse-arguments))
+
+(defun ecasound-iam-pcomplete-parse-arguments ()
+  "Parse arguments in the current region.
+\" :,\" are considered for splitting."
+  (let ((begin (save-excursion (comint-bol nil) (point)))
+       (end (point))
+       begins args)
+    (save-excursion
+      (goto-char begin)
+      (while (< (point) end)
+       (skip-chars-forward " \t\n,:")
+       (setq begins (cons (point) begins))
+       (let ((skip t))
+         (while skip
+           (skip-chars-forward "^ \t\n,:")
+           (if (eq (char-before) ?\\)
+               (skip-chars-forward " \t\n,:")
+             (setq skip nil))))
+       (setq args (cons (buffer-substring-no-properties
+                         (car begins) (point))
+                        args)))
+      (cons (reverse args) (reverse begins)))))
+
+(defun ecasound-input-file-or-device ()
+  "Return a list of possible completions for input device name."
+  (append (delq
+          nil
+          (mapcar
+           (lambda (elt)
+             (when (string-match
+                    (concat "^" (regexp-quote pcomplete-stub)) elt)
+               elt))
+           (list "alsa" "alsahw" "alsalb" "alsaplugin"
+                 "arts" "loop" "null" "stdin")))
+         (pcomplete-entries)))
+
+;;;; IAM commands
+
+(defun eci-map-find-args (arg map)
+  "Return the argument specification for ARG in MAP."
+  (let (result)
+    (while map
+      (if (string= (nth 1 (car map)) arg)
+         (setq result (nthcdr 3 (car map))
+               map nil)
+       (setq map (cdr map))))
+    result))
+
+(defun ecasound-echo-arg (arg)
+  "Display a chain operator parameter description from a eci-map-*-list
+variable."
+  (if arg
+      (let ((type (nth 5 arg)))
+       (message "%s%s%s, default %S%s%s"
+                (car arg)
+                (if type (format " (%S)" type) "")
+                (if (and (not (string= (nth 1 arg) ""))
+                         (not (string= (car arg) (nth 1 arg))))
+                    (format " (%s)" (nth 1 arg))
+                  "")
+                (nth 2 arg)
+                (if (nth 4 arg) (format " min %S" (nth 4 arg)) "")
+                (if (nth 3 arg) (format " max %S" (nth 3 arg)) "")))
+    (message "No help available")))
+
+\f
+;;; ECI --- The Ecasound Control Interface
+
+(defgroup eci nil
+  "Ecasound Control Interface."
+  :group 'ecasound)
+
+(defcustom eci-program (or (getenv "ECASOUND") "ecasound")
+  "*Program to invoke when doing `eci-init'."
+  :group 'eci
+  :type '(choice string (cons string string)))
+
+(defcustom eci-arguments '("-c" "-D" "-d:256")
+  "*Arguments used by `eci-init'."
+  :group 'eci
+  :type 'ecasound-args)
+
+(defvar eci-hide-output nil
+  "If non-nil, `eci-command' will remove the output generated.")
+
+(defmacro eci-hide-output (&rest eci-call)
+  "Hide the output of this ECI-call.
+If a daemon-channel is active, use that, otherwise set `eci-hide-output' to t.
+Argument ECI-CALL is a symbol followed by its aruments if any."
+  `(if (ecasound-daemon-p)
+       ,(append eci-call (list 'ecasound-daemon))
+     (let ((eci-hide-output t))
+       ,eci-call)))
+
+(defun eci-init ()
+  "Initialize a programmatic ECI session.
+Every call to this function results in a new sub-process being created
+according to `eci-program' and `eci-arguments'.  Returns the newly
+created buffer.
+The caller is responsible for terminating the subprocess at some point."
+  (save-excursion
+    (set-buffer
+     (apply 'make-comint
+           "eci-ecasound"
+           eci-program
+           nil
+           eci-arguments))
+    (ecasound-iam-mode)
+    (while (accept-process-output (get-buffer-process (current-buffer)) 1))
+    (if (eci-command "int-output-mode-wellformed")
+       (current-buffer))))
+
+(defun eci-interactive-startup ()
+  "Used to interactively startup a ECI session using `eci-init'.
+This will mostly be used for testing sessions and is equivalent
+to `ecasound'."
+  (interactive)
+  (switch-to-buffer (eci-init)))
+
+(defun ecasound-find-buffer (buffer-or-process)
+  (cond
+   ((bufferp buffer-or-process)
+    buffer-or-process)
+   ((processp buffer-or-process)
+    (process-buffer buffer-or-process))
+   ((and (eq major-mode 'ecasound-iam-mode)
+        (comint-check-proc (current-buffer)))
+    (current-buffer))
+   (t (error "Could not determine suitable ecasound buffer"))))
+
+(defun ecasound-find-parent (buffer-or-process)
+  (with-current-buffer (ecasound-find-buffer buffer-or-process)
+    (if ecasound-parent
+       ecasound-parent
+      (current-buffer))))
+
+(defun eci-command (command &optional buffer-or-process)
+  "Send a ECI command to a ECI host process.
+COMMAND is the string to be sent, without a newline character.
+If BUFFER-OR-PROCESS is nil, first look for a ecasound process in the current
+buffer, then for a ecasound buffer with the name *ecasound*,
+otherwise use the buffer or process supplied.
+Return the string we received in reply to the command except
+`eci-int-output-mode-wellformed-flag' is set, which means we can parse the
+output via `eci-parse' and return a meaningful value."
+  (interactive "sECI Command: ")
+  (let* ((buf (ecasound-find-buffer buffer-or-process))
+        (proc (get-buffer-process buf))
+        (ecasound-sending-command t))
+    (with-current-buffer buf
+      (let ((moving (= (point) (point-max))))
+       (setq eci-result 'waiting)
+       (goto-char (process-mark proc))
+       (insert command)
+       (let (comint-eol-on-send)
+         (comint-send-input))
+       (let ((here (point)) result)
+         (while (eq eci-result 'waiting)
+           (accept-process-output proc 0 30))
+         (setq result
+               (if eci-int-output-mode-wellformed-flag
+                   eci-result
+                 ;; Backward compatibility.  Just return the string
+                 (buffer-substring-no-properties here (save-excursion
+                                       ; Strange hack to avoid fields
+                                                        (forward-char -1)
+                                                        (beginning-of-line)
+                                                        (if (not (= here (point)))
+                                                            (forward-char -1))
+                                                        (point)))))
+         (if moving (goto-char (point-max)))
+         (when (and eci-hide-output result)
+           (ecasound-delete-last-in-and-output))
+         result)))))
+
+(defsubst eci-error-p ()
+  "Predicate which can be used to check if the last command produced an error."
+  (string= eci-return-type "e"))
+
+;;; ECI commands implemented as lisp functions
+
+(defeci int-cmd-list ()
+  ""
+  :cache ecasound-iam-commands
+  :cache-doc "Available Ecasound IAM commands.")
+
+(defeci run)
+
+(defeci start)
+
+(defeci cs-add ((chainsetup "sChainsetup to add: " "%s"))
+  "Adds a new chainsetup with name `name`."
+  :pcomplete doc)
+
+(defeci cs-connect ()
+  "Connect currently selected chainsetup to engine."
+  :pcomplete doc)
+
+(defeci cs-connected ()
+  "Returns the name of currently connected chainsetup."
+  :pcomplete doc)
+
+(defeci cs-disconnect ()
+  "Disconnect currently connected chainsetup."
+  :pcomplete doc)
+
+(defeci cs-forward
+  ((seconds
+    (if current-prefix-arg
+       (prefix-numeric-value current-prefix-arg)
+      (read-minibuffer (format "Time in seconds to forward %s: "
+                              (eci-hide-output eci-cs-selected)))) "%f")))
+
+(defeci cs-get-length ()
+  ""
+  :alias get-length)
+
+(defeci cs-get-length-samples ()
+  ""
+  :alias get-length-samples)
+
+(defeci cs-get-position ()
+  ""
+  :alias (cs-getpos getpos get-position))
+
+(defeci cs-index-select ((index "nChainsetup index: " "%d"))
+  ""
+  :alias cs-iselect)
+
+(defeci cs-is-valid ()
+  "Whether currently selected chainsetup is valid (=can be connected)?"
+  :pcomplete doc
+  (let ((val (eci-command "cs-is-valid" buffer-or-process)))
+    (if (interactive-p)
+       (message (format "Chainsetup is%s valid" (if (= val 0) "" " not"))))
+    val))
+
+(defun eci-cs-is-valid-p (&optional buffer-or-process)
+  "Predicate function used to determine chain setup validity."
+  (case (eci-cs-is-valid buffer-or-process)
+    (1 t)
+    (0 nil)
+    (otherwise (error "Unexcpected return value from cs-is-valid"))))
+
+(defeci cs-list ()
+  "Returns a list of all chainsetups."
+  :pcomplete doc
+  (let ((val (eci-command "cs-list" buffer-or-process)))
+    (if (interactive-p)
+       (message (concat "Available chainsetups: "
+                        (mapconcat #'identity val ", "))))
+    val))
+
+(defeci cs-load ((filename "fChainsetup filename: " "%s"))
+  "Adds a new chainsetup by loading it from file FILENAME.
+FILENAME is then the selected chainsetup."
+  :pcomplete (pcomplete-here (pcomplete-entries)))
+
+(defeci cs-remove ()
+  "Removes currently selected chainsetup."
+  :pcomplete doc)
+
+(defeci cs-rewind
+  ((seconds
+    (if current-prefix-arg
+       (prefix-numeric-value current-prefix-arg)
+      (read-minibuffer "Time in seconds to rewind chainsetup: ")) "%f"))
+  "Rewinds the current chainsetup position by `time-in-seconds` seconds."
+  :pcomplete doc
+  :alias (rewind rw))
+
+(defeci cs-save)
+
+(defeci cs-save-as ((filename "FChainsetup filename: " "%s"))
+  "Saves currently selected chainsetup to file FILENAME."
+  :pcomplete (pcomplete-here (pcomplete-entries)))
+
+(defeci cs-selected ()
+  "Returns the name of currently selected chainsetup."
+  :pcomplete doc
+  (let ((val (with-current-buffer (ecasound-find-parent buffer-or-process)
+              (setq eci-cs-selected (eci-command "cs-selected"
+                                                 buffer-or-process)))))
+    (if (interactive-p)
+       (message (format "Selected chainsetup: %s" val)))
+    val))
+
+(defeci cs-status)
+
+(defeci c-add ((chains "sChain(s) to add: " "%s"))
+  "Adds a set of chains.  Added chains are automatically selected.
+If argument CHAINS is a list, its elements are concatenated with ','.")
+
+(defeci c-clear ()
+  "Clear selected chains by removing all chain operators and controllers.
+Doesn't change how chains are connected to inputs and outputs."
+  :pcomplete doc)
+
+(defun ecasound-read-list (prompt list)
+  "Interactively prompt for a number of inputs until empty string.
+PROMPT is used as prompt and LIST is a list of choices to choose from."
+  (let ((avail list)
+       result current)
+    (while
+       (and avail
+            (not
+             (string=
+              (setq current (completing-read prompt (mapcar #'list avail)))
+              "")))
+      (setq result (cons current result)
+           avail (delete current avail)))
+    (nreverse result)))
+
+(defeci c-deselect
+  ((chains (ecasound-read-list "Chain to deselect: " (eci-c-selected)) "%s"))
+  "Deselects chains."
+  :pcomplete (while (pcomplete-here (eci-c-selected))))
+
+(defeci c-list ()
+  "Returns a list of all chains.")
+
+(defeci c-mute ()
+  "Toggle chain muting.  When chain is muted, all data that goes
+through is muted."
+  :pcomplete doc)
+
+(defeci c-select ((chains (ecasound-read-list "Chain: " (eci-c-list)) "%s"))
+  "Selects chains.  Other chains are automatically deselected."
+  :pcomplete doc)
+
+(defeci c-selected ()
+  ""
+  (let ((val (eci-command "c-selected" buffer-or-process)))
+    (if (interactive-p)
+       (if (null val)
+           (message "No selected chains")
+         (message (concat "Selected chains: "
+                          (mapconcat #'identity val ", ")))))
+    val))
+
+(defeci c-select-all ()
+  "Selects all chains."
+  :pcomplete doc)
+
+(defeci cs-select
+  ((chainsetup
+    (completing-read "Chainsetup: " (mapcar #'list (eci-cs-list)))
+    "%s"))
+  ""
+  :pcomplete (pcomplete-here (eci-hide-output eci-cs-list)))
+
+(defeci ai-add
+  ((ifstring
+    (let ((file (read-file-name "Input filename: ")))
+      (if (file-exists-p file)
+         (expand-file-name file)
+       file))
+    "%s"))
+  "Adds a new input object."
+  :pcomplete (pcomplete-here (ecasound-input-file-or-device)))
+
+(defeci ai-attach ()
+  "Attaches the currently selected audio input object to all selected chains."
+  :pcomplete doc)
+
+(defeci ai-forward
+  ((seconds
+    (if current-prefix-arg
+       (prefix-numeric-value current-prefix-arg)
+      (read-minibuffer (format "Time in seconds to forward %s: "
+                              (eci-hide-output eci-ai-selected)))) "%f"))
+  "Selected audio input object is forwarded by SECONDS.
+Time should be given as a floating point value (eg. 0.001 is the same as 1ms)."
+  :pcomplete doc
+  :alias ai-fw)
+
+(defeci ai-rewind
+  ((seconds
+    (if current-prefix-arg
+       (prefix-numeric-value current-prefix-arg)
+      (read-minibuffer (format "Time in seconds to rewind %s: "
+                              (eci-hide-output eci-ai-selected)))) "%f"))
+  "Selected audio input object is rewinded by SECONDS.
+Time should be given as a floating point value (eg. 0.001 is the same as 1ms)."
+  :pcomplete doc
+  :alias ai-rw)
+
+(defeci ai-index-select ((index "nAudio Input index: " "%d"))
+  "Select some audio input object based on a short index.
+Especially file names can be rather long.  This command can be used to avoid
+typing these long names when selecting audio objects.
+INDEX is an integer value, where 1 refers to the first audio input.
+You can use `eci-ai-list' to get a full list of currently available inputs."
+  :pcomplete doc
+  :alias ai-iselect)
+
+(defeci ai-list)
+
+(defeci ai-remove ()
+  "Removes the currently selected audio input object from the chainsetup."
+  :pcomplete doc)
+(defeci ao-remove ()
+  "Removes the currently selected audio output object from the chainsetup."
+  :pcomplete doc)
+
+(defeci ai-select ((name "sAudio Input Object name: " "%s"))
+  "Selects an audio object.
+NAME refers to the string used when creating the object.  Note! All input
+object names are required to be unique.  Similarly all output names need to be
+unique.  However, it's possible that the same object name exists both as an
+input and as an output."
+  :pcomplete (pcomplete-here (eci-hide-output eci-ai-list)))
+
+(defeci ai-selected ()
+  "Returns the name of the currently selected audio input object."
+  :pcomplete doc)
+
+(defeci ao-add ((filename "FOutput filename: " "%s"))
+  ""
+  :pcomplete (pcomplete-here (ecasound-input-file-or-device)))
+
+(defeci ao-add-default)
+
+(defeci ao-attach ()
+  "Attaches the currently selected audio output object to all selected chains."
+  :pcomplete doc)
+
+(defeci ao-forward
+  ((seconds
+    (if current-prefix-arg
+       (prefix-numeric-value current-prefix-arg)
+      (read-minibuffer (format "Time in seconds to forward %s: "
+                              (eci-hide-output eci-ao-selected)))) "%f"))
+  "Selected audio output object is forwarded by SECONDS.
+Time should be given as a floating point value (eg. 0.001 is the same as 1ms)."
+  :pcomplete doc
+  :alias ao-fw)
+
+(defeci ao-index-select ((index "nAudio Output index: " "%d"))
+  "Select some audio output object based on a short index.
+Especially file names can be rather long.  This command can be used to avoid
+typing these long names when selecting audio objects.
+INDEX is an integer value, where 1 refers to the first audio output.
+You can use `eci-ao-list' to get a full list of currently available outputs."
+  :pcomplete doc
+  :alias ao-iselect)
+
+(defeci ao-list)
+
+(defeci ao-rewind
+  ((seconds
+    (if current-prefix-arg
+       (prefix-numeric-value current-prefix-arg)
+      (read-minibuffer (format "Time in seconds to rewind %s: "
+                              (eci-hide-output eci-ai-selected)))) "%f"))
+  "Selected audio output object is rewinded by SECONDS.
+Time should be given as a floating point value (eg. 0.001 is the same as 1ms)."
+  :pcomplete doc
+  :alias ai-rw)
+
+(defeci ao-select ((name "sAudio Output Object name: " "%s"))
+  "Selects an audio object.
+NAME refers to the string used when creating the object.  Note! All output
+object names need to be unique.  However, it's possible that the same object
+name exists both as an input and as an output."
+  :pcomplete (pcomplete-here (eci-hide-output eci-ao-list)))
+
+(defeci ao-selected ()
+  "Returns the name of the currently selected audio output object."
+  :pcomplete doc)
+
+(defeci engine-status ()
+  "Returns a string describing the engine status
+\(running, stopped, finished, error, not ready)."
+  :pcomplete doc
+  (with-current-buffer (ecasound-find-parent buffer-or-process)
+    (setq eci-engine-status (eci-command "engine-status" buffer-or-process))))
+
+(defmacro ecasound-complete-cop-map (map)
+  (let ((m (intern (format "eci-map-%S-list" map))))
+    `(progn
+       (cond
+       ((= pcomplete-last 2)
+        (pcomplete-next-arg)
+        (pcomplete-here
+         (sort (mapcar (lambda (elt) (nth 1 elt))
+                       (eci-hide-output ,m))
+               #'string-lessp)))
+       ((> pcomplete-last 2)
+        (ecasound-echo-arg
+         (nth (- pcomplete-last 3)
+              (eci-map-find-args
+               (pcomplete-arg -1) (eci-hide-output ,m)))))))))
+
+(defeci cop-add
+  ((string
+    (if current-prefix-arg
+       (read-string "Chainop to add: " "-")
+      (let* ((cop
+             (completing-read
+              "Chain operator: "
+              (append (eci-hide-output eci-map-cop-list)
+                      (eci-hide-output eci-map-ladspa-list)
+                      (eci-hide-output eci-map-preset-list))))
+            (entry (or (assoc cop (eci-map-cop-list))
+                       (assoc cop (eci-map-ladspa-list))
+                       (assoc cop (eci-map-preset-list))))
+            (arg (nth 1 entry)))
+       (concat
+        (cond
+         ((assoc cop (eci-map-cop-list))
+          (concat "-" arg ":"))
+         ((assoc cop (eci-map-ladspa-list))
+          (concat "-el:" arg ","))
+         ((assoc cop (eci-map-preset-list))
+          (concat "-pn:" arg ",")))
+        (mapconcat #'ecasound-read-copp (nthcdr 3 entry) ","))))
+    "%s"))
+  ""
+  :pcomplete
+  (progn
+    (cond
+     ((= pcomplete-last 1)
+      (pcomplete-here
+       (append
+       '("-el:" "-pn:")
+       (mapcar
+        (lambda (elt)
+          (concat "-" (nth 1 elt) ":"))
+        (eci-hide-output eci-map-cop-list)))))
+     ((string= (pcomplete-arg) "-el")
+      (ecasound-complete-cop-map ladspa))
+     ((string= (pcomplete-arg) "-pn")
+      (ecasound-complete-cop-map preset))
+     ((> pcomplete-last 1)
+      (ecasound-echo-arg
+       (nth (- pcomplete-last 2)
+           (eci-map-find-args
+            (substring (pcomplete-arg) 1)
+            (eci-hide-output eci-map-cop-list))))))
+    (throw 'pcompleted t)))
+
+(defeci cop-list)
+
+(defeci cop-remove)
+
+(defeci cop-select
+  ((index "nChainop to select: " "%d")))
+
+(defeci cop-selected)
+
+;; FIXME: Command seems to be broken in CVS.
+(defeci cop-set ((cop "nChainop id: " "%d")
+                (copp "nParameter id: " "%d")
+                (value "nValue: " "%f"))
+  "Changes the value of a single chain operator parameter.
+Unlike other chain operator commands, this can also be used during processing."
+  :pcomplete doc)
+
+(defeci ctrl-add
+  ((string
+    (if current-prefix-arg
+       (read-string "Controller to add: " "-")
+      (let ((ctrl (assoc
+                  (completing-read
+                   "Chain operator controller controller: "
+                   (eci-hide-output eci-map-ctrl-list))
+                  (eci-hide-output eci-map-ctrl-list))))
+       (concat "-" (nth 1 ctrl) ":"
+               (mapconcat #'ecasound-read-copp (nthcdr 3 ctrl) ","))))
+    "%s")))
+
+(defeci ctrl-select
+  ((index "nController to select: " "%d")))
+
+(defeci copp-select
+  ((index "nChainop parameter to select: " "%d")))
+
+(defeci copp-get)
+
+(defeci copp-set
+  ((value "nValue for Chain operator parameter: " "%f")))
+
+;;;; ECI Examples
+
+(defun eci-example ()
+  "Implements the example given in the ECI documentation."
+  (interactive)
+  (save-current-buffer
+    (set-buffer (eci-init))
+    (display-buffer (current-buffer))
+    (eci-cs-add "play_chainsetup")
+    (eci-c-add "1st_chain")
+    (call-interactively #'eci-ai-add)
+    (eci-ao-add "/dev/dsp")
+    (eci-cop-add "-efl:100")
+    (eci-cop-select 1) (eci-copp-select 1)
+    (eci-cs-connect)
+    (eci-command "start")
+    (sit-for 1)
+    (while (and (string= (eci-engine-status) "running")
+               (< (eci-get-position) 15))
+      (eci-copp-set (+ (eci-copp-get) 500))
+      (sit-for 1))
+    (eci-command "stop")
+    (eci-cs-disconnect)
+    (message (concat "Chain operator status: "
+                      (eci-command "cop-status")))))
+
+(defun eci-make-temp-file-name (suffix)
+  (concat (make-temp-name
+          (expand-file-name "emacs-eci" temporary-file-directory))
+         suffix))
+
+(defun ecasound-read-from-minibuffer (prompt default)
+  (let ((result (read-from-minibuffer
+                (format "%s (default %S): " prompt default)
+                nil nil nil nil default)))
+    (if (and result (not (string= result "")))
+       result
+      default)))
+
+(defconst ecasound-signalview-clipped-threshold (- 1.0 (/ 1.0 16384)))
+
+(defconst ecasound-signalview-bar-length 55)
+
+(defun ecasound-position-to-string (secs &optional long)
+  "Convert a floating point position value in SECS to a string.
+If optional argument LONG is non-nil, produce a full 00:00.00 string,
+otherwise ignore zeors as well as colons and dots on the left side."
+  (let ((str (format "%02d:%02d.%02d"
+                    (/ secs 60)
+                    (% (round (floor secs)) 60)
+                    (* (- secs (floor secs)) 100))))
+    (if long
+       str
+      (let ((idx 0) (len (1- (length str))))
+       (while (and (< idx len)
+                   (let ((ch (aref str idx)))
+                     (or (eq ch ?0) (eq ch ?:) (eq ch ?.))))
+         (incf idx))
+       (substring str idx)))))
+
+(defun ecasound-signalview (bufsize format input output)
+  "Interactively view the singal of a audio stream.
+After invokation, this function displays the signal level of the individual
+channels in INPUT based on the information given in FORMAT."
+  (interactive
+   (list
+    (ecasound-read-from-minibuffer "Buffersize" "128")
+    (ecasound-read-from-minibuffer "Format" "s16_le,2,44100,i")
+    (let ((file (read-file-name "Input: ")))
+      (if (file-exists-p file)
+         (expand-file-name file)
+       file))
+    (ecasound-read-from-minibuffer "Output" "null")))
+  (let* (;; THis saves time
+        (ecasound-parse-cleanup-buffer nil)
+        (handle (eci-init))
+        (channels (string-to-number (nth 1 (split-string format ","))))
+        (chinfo (make-vector channels nil)))
+    (dotimes (ch channels) (aset chinfo ch (cons 0 0)))
+    (eci-cs-add "signalview" handle)
+    (eci-c-add "analysis" handle)
+    (eci-cs-set-audio-format format handle)
+    (eci-ai-add input handle)
+    (eci-ao-add output handle)
+    (eci-cop-add "-evp" handle)
+    (eci-cop-add "-ev" handle)
+    (set-buffer (get-buffer-create "*Ecasound-signalview*"))
+    (erase-buffer)
+    (dotimes (ch channels)
+      (insert "---\n"))
+    (setq header-line-format
+        (list (concat "Channel#"
+                      (make-string (- ecasound-signalview-bar-length 3) 32)
+                      "| max-value  clipped")))
+    (set (make-variable-buffer-local 'ecasignalview-position) "unknown")
+    (set (make-variable-buffer-local 'ecasignalview-engine-status) "unknown")
+    (setq mode-line-format
+         (list
+          (list
+           (- ecasound-signalview-bar-length 3)
+           (format "Input: %s, output: %s" input output)
+           'ecasignalview-engine-status)
+          " | " 'ecasignalview-position))
+    (switch-to-buffer-other-window (current-buffer))
+    (eci-cs-connect handle)
+    (eci-start handle)
+    (sit-for 0.8)
+    (eci-cop-select 1 handle)
+    (while (string= (setq ecasignalview-engine-status
+                         (eci-engine-status handle)) "running")
+      (let ((inhibit-quit t) (inhibit-redisplay t))
+       (setq ecasignalview-position
+             (ecasound-position-to-string (eci-cs-get-position handle) t))
+       (delete-region (point-min) (point-max))
+       (dotimes (ch channels)
+         (insert (format "ch%d: " (1+ ch)))
+         (let ((val (progn (eci-copp-select (1+ ch) handle)
+                           (eci-copp-get handle)))
+               (bl ecasound-signalview-bar-length))
+           (insert
+            (concat
+             (make-string (round (* val bl)) ?*)
+             (make-string (- bl (round (* val bl))) ? )))
+           (if (> val (car (aref chinfo ch)))
+               (setcar (aref chinfo ch) val))
+           (if (> val ecasound-signalview-clipped-threshold)
+             (incf (cdr (aref chinfo ch))))
+           (insert (format "| %.4f     %d\n" (car (aref chinfo ch))
+                           (cdr (aref chinfo ch))))))
+       (goto-char (point-min)))
+      (sit-for 0.1)
+      (fit-window-to-buffer))
+    (goto-char (point-max))
+    (let ((pos (point)))
+      (insert
+       (nth 2
+           (nth 2
+                (nthcdr 2
+                        (assoc "Volume analysis"
+                               (assoc "analysis"
+                                      (eci-cop-status handle)))))))
+      (goto-char pos))
+    (recenter channels)
+    (fit-window-to-buffer)))
+
+(defun ecasound-normalize (filename)
+  "Normalize a audio file using ECI."
+  (interactive "fFile to normalize: ")
+  (let ((tmpfile (eci-make-temp-file-name ".wav")))
+    (unwind-protect
+       (with-current-buffer (eci-init)
+         (display-buffer (current-buffer)) (sit-for 1)
+         (eci-cs-add "analyze") (eci-c-add "1")
+         (eci-ai-add filename) (eci-ao-add tmpfile)
+         (eci-cop-add "-ev")
+         (message "Analyzing sample data...")
+         (eci-cs-connect) (eci-run)
+         (eci-cop-select 1) (eci-copp-select 2)
+         (let ((gainfactor (eci-copp-get)))
+           (eci-cs-disconnect)
+           (if (<= gainfactor 1)
+               (message "File already normalized!")
+             (eci-cs-add "apply") (eci-c-add "1")
+             (eci-ai-add tmpfile) (eci-ao-add filename)
+             (eci-cop-add "-ea:100")
+             (eci-cop-select 1)
+             (eci-copp-select 1)
+             (eci-copp-set (* gainfactor 100))
+             (eci-cs-connect) (eci-run) (eci-cs-disconnect)
+             (message "Done"))))
+      (if (file-exists-p tmpfile)
+         (delete-file tmpfile)))))
+
+;;; Utility functions for converting strings to data-structures.
+
+(defvar eci-cop-status-header
+  "### Chain operator status (chainsetup '\\([^']+\\)') ###\n")
+
+(defun eci-process-cop-status (string)
+  (with-temp-buffer
+    (insert string) (goto-char (point-min))
+    (when (re-search-forward eci-cop-status-header nil t)
+      (let (result)
+       (while (re-search-forward "Chain \"\\([^\"]+\\)\":\n" nil t)
+         (let ((c (match-string-no-properties 1)) chain)
+           (while (re-search-forward
+                   "\t\\([0-9]+\\)\\. \\(.+\\): \\(.*\\)\n?" nil t)
+             (let ((n (string-to-number (match-string 1)))
+                   (name (match-string-no-properties 2))
+                   (args
+                    (mapcar
+                     (lambda (elt)
+                       (when (string-match
+                              "\\[\\([0-9]+\\)\\] \\(.*\\) \\([0-9.-]+\\)$"
+                              elt)
+                         (list (match-string-no-properties 2 elt)
+                               (string-to-number (match-string 1 elt))
+                               (string-to-number (match-string 3 elt)))))
+                     (split-string
+                      (match-string-no-properties 3) ", "))))
+               (if (looking-at "\tStatus info:\n")
+                   (setq args
+                         (append
+                          args
+                          (list
+                           (list
+                            "Status info" nil
+                            (buffer-substring
+                             (progn (forward-line 1) (point))
+                             (or (re-search-forward "\n\n" nil t)
+                                 (point-max))))))))
+               (setq chain (cons (append (list name n) args) chain))))
+           (setq result (cons (reverse (append chain (list c))) result))))
+       result))))
+
+(defun eci-process-map-list (string)
+  "Parse the output of a map-xxx-list ECI command and return an alist.
+STRING is the string returned by a map-xxx-list command."
+  (mapcar
+   (lambda (elt)
+     (append
+      (list (nth 1 elt) (nth 0 elt) (nth 2 elt))
+      (let (res (count (string-to-number (nth 3 elt))))
+       (setq elt (nthcdr 4 elt))
+       (while (> count 0)
+         (setq
+          res
+          (cons
+           (list (nth 0 elt) (nth 1 elt)
+                 (string-to-number (nth 2 elt)) ;; default value
+                 (when (string= (nth 3 elt) "1")
+                   (string-to-number (nth 4 elt)))
+                 (when (string= (nth 5 elt) "1")
+                   (string-to-number (nth 6 elt)))
+                 (cond
+                  ((string= (nth 7 elt) "1")
+                   'toggle)
+                  ((string= (nth 8 elt) "1")
+                   'integer)
+                  ((string= (nth 9 elt) "1")
+                   'logarithmic)
+                  ((string= (nth 10 elt) "1")
+                   'output))) res)
+          elt (nthcdr 11 elt)
+          count (1- count)))
+       (reverse res))))
+   (mapcar (lambda (str) (split-string str ","))
+          (split-string string "\n"))))
+
+(defeci cs-set-audio-format
+  ((format (ecasound-read-from-minibuffer
+           "Audio format" "s16_le,2,44100,i") "%s"))
+  "Set the default sample parameters for currently selected chainsetup.
+For example cd-quality audio would be \"16,2,44100\"."
+  :pcomplete doc)
+
+(defeci cop-register)
+(defeci preset-register)
+(defeci ctrl-register)
+
+(defeci cop-status)
+
+(defeci ladspa-register)
+
+(defun ecasound-read-copp (copp)
+  "Interactively read one chainop parameter."
+  (let* ((completion-ignore-case t)
+        (default (format "%S" (nth 2 copp)))
+        (answer
+         (read-from-minibuffer
+          (concat
+           (car copp)
+           " (default " default "): ")
+          nil nil nil nil
+          default)))
+    (if (and answer (not (string= answer "")))
+       answer
+      default)))
+
+;;; ChainOp Editor
+
+(defvar ecasound-cop-edit-mode-map
+  (let ((map (make-keymap)))
+    (set-keymap-parent map widget-keymap)
+    map))
+
+(define-derived-mode ecasound-cop-edit-mode fundamental-mode "COP-edit"
+  "A major mode for editing ecasound chain operators.")
+
+(defun ecasound-cop-edit ()
+  "Edit the chain operator settings of the current session interactively.
+This is done using the ecasound-cop widget."
+  (interactive)
+  (let ((cb (current-buffer))
+       (chains (eci-cop-status)))
+    (switch-to-buffer-other-window (generate-new-buffer "*cop-edit*"))
+    (ecasound-cop-edit-mode)
+    (mapc
+     (lambda (chain)
+       (widget-insert (format "Chain %s:\n" (car chain)))
+       (mapc
+       (lambda (cop)
+         (apply 'widget-create 'ecasound-cop :buffer cb cop))
+       (cdr chain)))
+     chains)
+    (widget-setup)
+    (goto-char (point-min))))
+
+(define-widget 'ecasound-cop 'default
+  "A Chain Operator.
+:children is a list of ecasound-copp widgets."
+  :convert-widget
+  (lambda (widget)
+    (let ((args (widget-get widget :args)))
+      (when args
+       (widget-put widget :tag (car args))
+       (widget-put widget :cop-number (nth 1 args))
+       (widget-put widget :args (cddr args))))
+    widget)
+  :value-create
+  (lambda (widget)
+    (widget-put
+     widget :children
+     (mapcar
+      (lambda (copp-arg)
+       (apply 'widget-create-child-and-convert
+            widget '(ecasound-copp) copp-arg))
+      (widget-get widget :args))))
+  :format-handler
+  (lambda (widget escape)
+    (cond
+     ((eq escape ?i)
+      (widget-put
+       widget :cop-select
+       (widget-create-child-value
+       widget '(ecasound-cop-select) (widget-get widget :cop-number))))))
+  :format "%i %t\n%v")
+
+(define-widget 'ecasound-cop-select 'link
+  "Select this chain operator parameter."
+  :help-echo "RET to select."
+  :button-prefix ""
+  :button-suffix ""
+  :format "%[%v.%]"
+  :action
+  (lambda (widget &rest ignore)
+    (let ((buffer (widget-get (widget-get widget :parent) :buffer)))
+      (eci-cop-select (widget-value widget) buffer))))
+
+;;;; A Chain Operator Parameter Widget.
+
+; This is used as a component of the cop widget.
+
+(define-widget 'ecasound-copp 'number
+  "A Chain operator parameter."
+  :action 'ecasound-copp-action
+  :convert-widget 'ecasound-copp-convert
+  :format "  %i %v (%t)\n"
+  :format-handler 'ecasound-copp-format-handler
+  :size 10)
+
+(defun ecasound-copp-convert (widget)
+  "Convert args."
+  (let ((args (widget-get widget :args)))
+    (when args
+      (widget-put widget :tag (car args))
+      (widget-put widget :copp-number (nth 1 args))
+      (widget-put widget :value (nth 2 args))
+      (widget-put widget :args nil)))
+  widget)
+
+(defun ecasound-copp-format-handler (widget escape)
+  (cond
+   ((eq escape ?i)
+    (widget-put
+     widget
+     :copp-select
+     (widget-create-child-value
+      widget
+      '(ecasound-copp-select)
+      (widget-get widget :copp-number))))
+   ((eq escape ?s)
+    (widget-put
+     widget
+     :slider
+     (widget-create-child-value
+      widget
+      '(slider)
+      (string-to-number (widget-get widget :value)))))))
+
+(defun ecasound-copp-action (widget &rest ignore)
+  "Sets WIDGETs value in its associated ecasound buffer."
+  (let ((buffer (widget-get (widget-get widget :parent) :buffer)))
+    (if (widget-apply widget :match (widget-value widget))
+       (progn
+         (eci-cop-set (widget-get (widget-get widget :parent) :cop-number)
+                      (widget-get widget :copp-number)
+                      (widget-value widget)
+                      buffer))
+      (message "Invalid"))))
+
+(defvar ecasound-copp-select-keymap
+  (let ((map (copy-keymap widget-keymap)))
+    (define-key map "+" 'ecasound-copp-increase)
+    (define-key map "-" 'ecasound-copp-decrease)
+    map)
+  "Keymap used inside an copp.")
+
+(defun ecasound-copp-increase (pos &optional event)
+  (interactive "@d")
+  ;; BUG, if we do this, the field is suddently no longer editable, why???
+  (let ((widget (widget-get (widget-at pos) :parent)))
+    (widget-value-set
+     widget
+     (+ (widget-value widget) 1))
+    (widget-apply widget :action)
+    (widget-setup)))
+
+(defun ecasound-copp-decrease (pos &optional event)
+  (interactive "@d")
+  (let ((widget (widget-get (widget-at pos) :parent)))
+    (widget-value-set
+     widget
+     (- (widget-value widget) 1))
+    (widget-apply widget :action)
+    (widget-setup)))
+
+(define-widget 'ecasound-copp-select 'link
+  "Select this chain operator parameter."
+  :help-echo "RET to select, +/- to set in steps."
+  :keymap ecasound-copp-select-keymap
+  :format "%[%v%]"
+  :action 'ecasound-copp-select-action)
+
+(defun ecasound-copp-select-action (widget &rest ignore)
+  "Selects WIDGET in its associated ecasound buffer."
+  (let ((buffer (widget-get (widget-get (widget-get widget :parent) :parent)
+                           :buffer)))
+    (eci-copp-select (widget-get widget :value) buffer)))
+
+(define-widget 'slider 'default
+  "A slider."
+  :action 'widget-slider-action
+  :button-prefix ""
+  :button-suffix ""
+  :format "(%[%v%])"
+  :keymap
+  (let ((map (copy-keymap widget-keymap)))
+    (define-key map "\C-m" 'widget-slider-press)
+    (define-key map "+" 'widget-slider-increase)
+    (define-key map "-" 'widget-slider-decrease)
+    map)
+  :value-create 'widget-slider-value-create
+  :value-delete 'ignore
+  :value-get 'widget-value-value-get
+  :size 70
+  :value 0)
+
+(defun widget-slider-press (pos &optional event)
+  "Invoke slider at POS."
+  (interactive "@d")
+  (let ((button (get-char-property pos 'button)))
+    (if button
+       (widget-apply-action
+        (widget-value-set
+         button
+         (- pos (overlay-start (widget-get button :button-overlay))))
+        event)
+      (let ((command (lookup-key widget-global-map (this-command-keys))))
+        (when (commandp command)
+          (call-interactively command))))))
+
+(defun widget-slider-increase (pos &optional event)
+  "Increase slider at POS."
+  (interactive "@d")
+  (widget-slider-change pos #'+ 1 event))
+
+(defun widget-slider-decrease (pos &optional event)
+  "Decrease slider at POS."
+  (interactive "@d")
+  (widget-slider-change pos #'- 1 event))
+
+(defun widget-slider-change (pos function value &optional event)
+  "Change slider at POS by applying FUNCTION to old-value and VALUE."
+  (let ((button (get-char-property pos 'button)))
+    (if button
+       (widget-apply-action
+        (widget-value-set button (apply function (widget-value button) value))
+        event)
+      (let ((command (lookup-key widget-global-map (this-command-keys))))
+        (when (commandp command)
+          (call-interactively command))))))
+
+(defun widget-slider-action (widget &rest ignore)
+  "Set the current :parent value to :value."
+  (widget-value-set (widget-get widget :parent)
+                   (widget-value widget)))
+
+(defun widget-slider-value-create (widget)
+  "Create a sliders value."
+  (let ((size (widget-get widget :size))
+        (value (string-to-int (format "%.0f" (widget-get widget :value))))
+        (from (point)))
+    (insert-char ?\  value)
+    (insert-char ?\| 1)
+    (insert-char ?\  (- size value 1))))
+
+\f
+;;; Ecasound .ewf major mode
+
+(defgroup ecasound-ewf nil
+  "Ecasound .ewf file mode related variables and faces."
+  :prefix "ecasound-ewf-"
+  :group 'ecasound)
+
+(defcustom ecasound-ewf-output-device "/dev/dsp"
+  "*Default output device used for playing .ewf files."
+  :group 'ecasound-ewf
+  :type 'string)
+
+(defface ecasound-ewf-keyword-face '((t (:foreground "IndianRed")))
+  "The face used for highlighting keywords."
+  :group 'ecasound-ewf)
+
+(defface ecasound-ewf-time-face '((t (:foreground "Cyan")))
+  "The face used for highlighting time information."
+  :group 'ecasound-ewf)
+
+(defface ecasound-ewf-file-face '((t (:foreground "Green")))
+  "The face used for highlighting the filname."
+  :group 'ecasound-ewf)
+
+(defface ecasound-ewf-boolean-face '((t (:foreground "Orange")))
+  "The face used for highlighting boolean values."
+  :group 'ecasound-ewf)
+
+(defvar ecasound-ewf-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\t" 'pcomplete)
+    (define-key map "\C-c\C-p" 'ecasound-ewf-play)
+    map)
+  "Keymap for `ecasound-ewf-mode'.")
+
+(defvar ecasound-ewf-mode-syntax-table
+  (let ((st (make-syntax-table)))
+    (modify-syntax-entry ?# "<" st)
+    (modify-syntax-entry ?\n ">" st)
+    st)
+  "Syntax table for `ecasound-ewf-mode'.")
+
+(defvar ecasound-ewf-font-lock-keywords
+  '(("^\\s-*\\(source\\)[^=]+=\\s-*\\(.*\\)$"
+     (1 'ecasound-ewf-keyword-face)
+     (2 'ecasound-ewf-file-face))
+    ("^\\s-*\\(offset\\)[^=]+=\\s-*\\([0-9.]+\\)$"
+     (1 'ecasound-ewf-keyword-face)
+     (2 'ecasound-ewf-time-face))
+    ("^\\s-*\\(start-position\\)[^=]+=\\s-*\\([0-9.]+\\)$"
+     (1 'ecasound-ewf-keyword-face)
+     (2 'ecasound-ewf-time-face))
+    ("^\\s-*\\(length\\)[^=]+=\\s-*\\([0-9.]+\\)$"
+     (1 'ecasound-ewf-keyword-face)
+     (2 'ecasound-ewf-time-face))
+    ("^\\s-*\\(looping\\)[^=]+=\\s-*\\(true\\|false\\)$"
+     (1 'ecasound-ewf-keyword-face)
+     (2 'ecasound-ewf-boolean-face)))
+  "Keyword highlighting specification for `ecasound-ewf-mode'.")
+
+;;;###autoload
+(define-derived-mode ecasound-ewf-mode fundamental-mode "EWF"
+  "A major mode for editing ecasound .ewf files."
+  (set (make-local-variable 'comment-start) "# ")
+  (set (make-local-variable 'comment-start-skip) "#+\\s-*")
+  (set (make-local-variable 'font-lock-defaults)
+       '(ecasound-ewf-font-lock-keywords))
+  (ecasound-ewf-setup-pcomplete))
+
+;;; .ewf-mode pcomplete support
+
+(defun ecasound-ewf-keyword-completion-function ()
+  (pcomplete-here
+   (list "source" "offset" "start-position" "length" "looping")))
+
+(defun pcomplete/ecasound-ewf-mode/source ()
+  (pcomplete-here (pcomplete-entries)))
+
+(defun pcomplete/ecasound-ewf-mode/offset ()
+  (message "insert audio object at offset (seconds) [read,write]")
+  (throw 'pcompleted t))
+
+(defun pcomplete/ecasound-ewf-mode/start-position ()
+  (message "start offset inside audio object (seconds) [read]")
+  (throw 'pcompleted t))
+
+(defun pcomplete/ecasound-ewf-mode/length ()
+  (message "how much of audio object data is used (seconds) [read]")
+  (throw 'pcompleted t))
+
+(defun pcomplete/ecasound-ewf-mode/looping ()
+  (pcomplete-here (list "true" "false")))
+
+(defun ecasound-ewf-parse-arguments ()
+  "Parse whitespace separated arguments in the current region."
+  (let ((begin (save-excursion (beginning-of-line) (point)))
+       (end (point))
+       begins args)
+    (save-excursion
+      (goto-char begin)
+      (while (< (point) end)
+       (skip-chars-forward " \t\n=")
+       (setq begins (cons (point) begins))
+       (let ((skip t))
+         (while skip
+           (skip-chars-forward "^ \t\n=")
+           (if (eq (char-before) ?\\)
+               (skip-chars-forward " \t\n=")
+             (setq skip nil))))
+       (setq args (cons (buffer-substring-no-properties
+                         (car begins) (point))
+                        args)))
+      (cons (reverse args) (reverse begins)))))
+
+(defun ecasound-ewf-setup-pcomplete ()
+  (set (make-local-variable 'pcomplete-parse-arguments-function)
+       'ecasound-ewf-parse-arguments)
+  (set (make-local-variable 'pcomplete-command-completion-function)
+       'ecasound-ewf-keyword-completion-function)
+  (set (make-local-variable 'pcomplete-command-name-function)
+       (lambda ()
+        (pcomplete-arg 'first)))
+  (set (make-local-variable 'pcomplete-arg-quote-list)
+       (list ? )))
+
+;;; Interactive commands
+
+;; FIXME: Make it use ECI.
+(defun ecasound-ewf-play ()
+  (interactive)
+  (let ((ecasound-arguments (list "-c"
+                                 "-i" buffer-file-name
+                                 "-o" ecasound-ewf-output-device)))
+    (and (buffer-modified-p)
+        (y-or-n-p "Save file before playing? ")
+        (save-buffer))
+    (ecasound "*Ecasound-ewf Player*")))
+
+(add-to-list 'auto-mode-alist (cons "\\.ewf$" 'ecasound-ewf-mode))
+
+;; Local variables:
+;; mode: outline-minor
+;; outline-regexp: ";;;;* \\|\f"
+;; End:
+
+(provide 'ecasound)
+
+;;; ecasound.el ends here
+
diff --git a/emacs_el/emacs-wiki.el b/emacs_el/emacs-wiki.el
new file mode 100644 (file)
index 0000000..99a7ef2
--- /dev/null
@@ -0,0 +1,3930 @@
+;;; emacs-wiki.el --- Maintain a local Wiki using Emacs-friendly markup
+
+;; Copyright (C) 2001, 2002, 2003 John Wiegley (johnw AT gnu DOT org)
+
+;; Emacs Lisp Archive Entry
+;; Filename: emacs-wiki.el
+;; Version: 2.40
+;; Date: Sun 24-Nov-2002
+;; Keywords: hypermedia
+;; Author: John Wiegley (johnw AT gnu DOT org)
+;;         Alex Schroeder (alex AT gnu DOT org)
+;; Maintainer: Damien Elmes (emacswiki AT repose DOT cx)
+;; Description: Maintain Emacs-friendly Wikis in a local directory
+;; URL: http://repose.cx/emacs/wiki
+;; Compatibility: Emacs20, Emacs21, XEmacs21
+
+;; This file is not part of GNU Emacs.
+
+;; The canonical URL for this file is now:
+;;   http://repose.cx/emacs/wiki
+;; Older copies and other modules which use emacs-wiki can be found at the
+;; original author's page:
+;;   http://www.gci-net.com/users/j/johnw/EmacsResources.html
+
+;; This 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 is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+;; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+;; for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+;; MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; Wiki is a concept, more than a thing.  It is a way of creating
+;; document pages using plain text markup and simplified hyperlinking.
+
+;; By typing a name in MixedCase, a hyperlink is automatically created
+;; to the document "MixedCase".  Pressing return on that name will
+;; create the file if it doesn't exist, or visit it if it does.
+
+;; The markup used by emacs-wiki is intended to be very friendly to
+;; people familiar with Emacs.  Type C-h v emacs-wiki-publishing-markup
+;; after this mode is loaded for how to get started.
+
+;; * Startup
+
+;; To begin using emacs-wiki, put this in your .emacs file:
+
+;;   (load "emacs-wiki")
+
+;; Now you can type M-x emacs-wiki-find-file, give it a WikiName (or
+;; just hit return) and start typing!
+
+;; You should also type M-x customize-group, and give the name
+;; "emacs-wiki".  Change it to suite your preferences.  Each of the
+;; options has its own documentation.
+
+;; * Keystroke summary
+
+;; Here is a summary of keystrokes available in every Wiki buffer:
+
+;;   C-c C-a    jump to an index of all the Wiki pages
+;;   C-c C-b    show all pages that reference this page
+;;   C-c C-s    search for a word in your Wiki pages
+;;   C-c C-f    jump to another Wiki page; prompts for the name
+;;   C-c C-l    highlight/refresh the current buffer
+;;   C-c C-p    publish any Wiki pages that have changed as HTML
+;;   C-c C-r    rename wiki link at point
+;;   C-c C-v    change wiki project
+;;   C-c C-D    delete wiki link at point (binding will only work on X)
+;;   C-c =      diff this page against the last backup version
+;;   TAB        move to the next Wiki reference
+;;   S-TAB      move to the previous Wiki reference
+
+;; * Using pcomplete
+
+;; If you have pcomplete loaded, you can type M-TAB to complete Wiki
+;; names.  Hitting M-TAB twice or more time in succession, will cycle
+;; through all of the possibilities.  You can download pcomplete from
+;; my Website:
+
+;;   http://www.gci-net.com/~johnw/emacs.html
+
+;; * ChangeLog support
+
+;; If you use a ChangeLog (C-x 4 a) within one of your Wiki
+;; directories, it will be used for notifying visitors to your wiki of
+;; recent changes.
+
+;; * Changing title or stylesheet
+
+;; For convenience, if you want to change the visible title, or the
+;; stylesheet, used by a certain Wiki page during HTML publishing,
+;; just put:
+
+;; #title Hello there
+;; #style hello.css
+
+;; at the top of the page.
+
+;; * <lisp> tricks
+
+;; <lisp></lisp> tags can be used, not only to evaluate forms for
+;; insertion at that point, but to influence the publishing process in
+;; many ways.  Here's another way to change a page's stylesheet:
+
+;; <lisp>
+;; (ignore
+;;   ;; use special.css for this Wiki page
+;;   (set (make-variable-buffer-local 'emacs-wiki-style-sheet)
+;;        "<link rel=\"stylesheet\" type=\"text/css\" href=\"special.css\">"))
+;; </lisp>
+
+;; The 'ignore' is needed so nothing is inserted where the <lisp> tag
+;; occurred.  Also, there should be no blank lines before or after the
+;; tag (to avoid empty paragraphs from being created).  The best place
+;; to put this would be at the very top or bottom of the page.
+
+;; * Sub-lists?
+
+;; There is no inherent support for sub-lists, since I couldn't think
+;; of a simple way to do it.  But if you really need them, here's a
+;; trick you can use:
+
+;; - Hello
+;;   <ul>
+;;   <li>There
+;;   <li>My friend
+;;   </ul>
+
+;;; Thanks
+
+;; Alex Schroeder (alex AT gnu DOT org), current author of "wiki.el".
+;;   His latest version is here:
+;;       http://www.geocities.com/kensanata/wiki/WikiMode.html
+;;
+;; Frank Gerhardt (Frank.Gerhardt AT web DOT de), author of the original wiki-mode
+;;   His latest version is here:
+;;       http://www.s.netic.de/fg/wiki-mode/wiki.el
+;;
+;; Thomas Link (<t.link AT gmx DOT at)
+
+;;; Code:
+
+;; The parts of this code, and work to be done:
+;;
+;; * setup emacs-wiki major mode
+;; * generate WikiName list
+;; * utility functions to extract link parts
+;; * open a page
+;; * navigate links in the buffer
+;; * visit a link
+;; * search Wiki pages for text/backlinks
+;; * index generation
+;; * buffer highlighting (using font-lock)
+;; * HTML publishing
+;;   - Allow for alternate markup tables: DocBook, xhtml, etc.
+;;   - <nop> used in a line of verse doesn't have effect
+;; * HTTP serving (using httpd.el)
+;;   - Diffing (look at using highlight-changes-mode and htmlify.el)
+;;   - Editing (requires implementing POST method for httpd.el)
+
+(defvar emacs-wiki-version "$Id"
+  "The version of emacs-wiki currently loaded")
+
+(require 'derived)
+
+;; for caddr etc
+;(eval-when-compile (require 'cl))
+
+;; load pcomplete if it's available
+(load "pcomplete" t t)
+
+(defvar emacs-wiki-under-windows-p (memq system-type '(ms-dos windows-nt)))
+
+;;; Options:
+
+(defgroup emacs-wiki nil
+  "Options controlling the behaviour of Emacs Wiki Mode.
+Wiki is a concept, more than a thing.  It is a way of creating
+document pages using plain text markup and simplified hyperlinking.
+
+By typing a name in MixedCase, a hyperlink is automatically created
+to the document \"MixedCase\".  Pressing return on that name will
+create the file if it doesn't exist, or visit it if it does.
+
+The markup used by emacs-wiki is intended to be very friendly to
+people familiar with Emacs.  See the documentation for the variable
+`emacs-wiki-publishing-markup' for a full description."
+  :group 'hypermedia)
+
+(defcustom emacs-wiki-mode-hook
+  (append (if (featurep 'table)
+             '(table-recognize))
+         (unless (featurep 'httpd)
+           '(emacs-wiki-use-font-lock)))
+  "A hook that is run when emacs-wiki mode is entered."
+  :type 'hook
+  :options '(emacs-wiki-use-font-lock
+            emacs-wiki-highlight-buffer
+            flyspell-mode
+            footnote-mode
+            highlight-changes-mode)
+  :group 'emacs-wiki)
+
+;;;###autoload
+(defcustom emacs-wiki-directories '("~/Wiki")
+  "A list of directories where Wiki pages can be found."
+  :require 'emacs-wiki
+  :type '(repeat :tag "Wiki directories" directory)
+  :group 'emacs-wiki)
+
+(defcustom emacs-wiki-default-page "WelcomePage"
+  "Name of the default page used by \\[emacs-wiki-find-file]."
+  :type 'string
+  :group 'emacs-wiki)
+
+(defcustom emacs-wiki-file-ignore-regexp
+  "\\`\\(\\.?#.*\\|.*,v\\|.*~\\|\\.\\.?\\)\\'"
+  "A regexp matching files to be ignored in Wiki directories."
+  :type 'regexp
+  :group 'emacs-wiki)
+
+(defcustom emacs-wiki-ignored-extensions-regexp
+  "\\.\\(bz2\\|gz\\|[Zz]\\)\\'"
+  "A regexp of extensions to omit from the ending of Wiki page name."
+  :type 'string
+  :group 'emacs-wiki)
+
+(defcustom emacs-wiki-interwiki-names
+  '(("GnuEmacs" . "http://www.gnu.org/software/emacs/emacs.html")
+    ("TheEmacsWiki" .
+     (lambda (tag)
+       (concat "http://www.emacswiki.org/cgi-bin/wiki.pl?"
+               (or tag "SiteMap"))))
+    ("MeatballWiki" .
+     (lambda (tag)
+       (concat "http://www.usemod.com/cgi-bin/mb.pl?"
+              (or tag "MeatballWiki")))))
+  "A table of WikiNames that refer to external entities.
+The format of this table is an alist, or series of cons cells.
+Each cons cell must be of the form:
+
+  (WIKINAME . STRING-OR-FUNCTION)
+
+The second part of the cons cell may either be a STRING, which in most
+cases should be a URL, or a FUNCTION.  If a function, it will be
+called with one argument: the tag applied to the Interwiki name, or
+nil if no tag was used.  If the cdr was a STRING and a tag is used,
+the tag is simply appended.
+
+Here are some examples:
+
+  (\"JohnWiki\" . \"http://alice.dynodns.net/wiki?\")
+
+Referring to [[JohnWiki#EmacsModules]] then really means:
+
+  http://alice.dynodns.net/wiki?EmacsModules
+
+If a function is used for the replacement text, you can get creative
+depending on what the tag is.  Tags may contain any alphabetic
+character, any number, % or _.  If you need other special characters,
+use % to specify the hex code, as in %2E.  All browsers should support
+this."
+  :type '(repeat (cons (string :tag "WikiName")
+                      (choice (string :tag "URL") function)))
+  :group 'emacs-wiki)
+
+(defvar emacs-wiki-url-or-name-regexp nil
+  "Matches either a Wiki link or a URL.  This variable is auto-generated.")
+
+(defvar emacs-wiki-url-or-name-regexp-group-count nil
+  "Matches either a Wiki link or a URL.  This variable is auto-generated.")
+
+(defcustom emacs-wiki-extended-link-regexp
+  "\\[\\[\\([^] \t\n]+\\)\\]\\(\\[\\([^]\n]+\\)\\]\\)?\\]"
+  "Regexp used to match [[extended][links]]."
+  :type 'regexp
+  :group 'emacs-wiki)
+
+(defun emacs-wiki-count-chars (string char)
+  (let ((i 0)
+       (l (length string))
+       (count 0))
+    (while (< i l)
+      (if (eq char (aref string i))
+         (setq count (1+ count)))
+      (setq i (1+ i)))
+    count))
+
+(defun emacs-wiki-set-sym-and-url-regexp (sym value)
+  (setq emacs-wiki-url-or-name-regexp
+       (concat "\\("
+               (if (eq sym 'emacs-wiki-name-regexp)
+                   value
+                 emacs-wiki-name-regexp) "\\|"
+               (if (eq sym 'emacs-wiki-name-regexp)
+                   (if (boundp 'emacs-wiki-url-regexp)
+                       emacs-wiki-url-regexp
+                     "")
+                 value) "\\)")
+       emacs-wiki-url-or-name-regexp-group-count
+       (- (emacs-wiki-count-chars
+           emacs-wiki-url-or-name-regexp ?\() 2))
+  (set sym value))
+
+(defcustom emacs-wiki-name-regexp
+  (concat "\\(" emacs-wiki-extended-link-regexp "\\|"
+         "\\<[A-Z][a-z]+\\([A-Z][a-z]+\\)+\\(#[A-Za-z0-9_%]+\\)?" "\\)")
+  "Regexp used to match WikiNames."
+  :type 'regexp
+  :set 'emacs-wiki-set-sym-and-url-regexp
+  :group 'emacs-wiki)
+
+(defcustom emacs-wiki-url-regexp
+  (concat "\\<\\(https?:/?/?\\|ftp:/?/?\\|gopher://\\|"
+         "telnet://\\|wais://\\|file:/\\|s?news:\\|"
+          "mailto:\\)"
+         "[^]  \n \"'()<>[^`{}]*[^]    \n \"'()<>[^`{}.,;]+")
+  "A regexp used to match URLs within a Wiki buffer."
+  :type 'regexp
+  :set 'emacs-wiki-set-sym-and-url-regexp
+  :group 'emacs-wiki)
+
+(defcustom emacs-wiki-browse-url-function 'browse-url
+  "Function to call to browse a URL."
+  :type 'function
+  :group 'emacs-wiki)
+
+(defcustom emacs-wiki-grep-command
+  "find %D -type f ! -name '*~' | xargs egrep -n -e \"\\<%W\\>\""
+  "The name of the program to use when grepping for backlinks.
+The string %D is replaced by `emacs-wiki-directories', space-separated.
+The string %W is replaced with the name of the Wiki page.
+
+Note: I highly recommend using glimpse to search large Wikis.  To use
+glimpse, install and edit a file called .glimpse_exclude in your home
+directory.  Put a list of glob patterns in that file to exclude Emacs
+backup files, etc.  Then, run the indexer using:
+
+  glimpseindex -o <list of Wiki directories>
+
+Once that's completed, customize this variable to have the following
+value:
+
+  glimpse -nyi \"%W\"
+
+Your searches will go much, much faster, especially for very large
+Wikis.  Don't forget to add a user cronjob to update the index at
+intervals."
+  :type 'string
+  :group 'emacs-wiki)
+
+(defvar emacs-wiki-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map [(control ?c) (control ?a)] 'emacs-wiki-index)
+    (define-key map [(control ?c) (control ?f)] 'emacs-wiki-find-file)
+    (define-key map [(control ?c) (control ?b)] 'emacs-wiki-backlink)
+    (define-key map [(control ?c) (control ?s)] 'emacs-wiki-search)
+    (define-key map [(control ?c) (control ?p)] 'emacs-wiki-publish)
+    (define-key map [(control ?c) (control ?v)] 'emacs-wiki-change-project)
+    (define-key map [(control ?c) (control ?r)]
+                                          'emacs-wiki-rename-link-at-point)
+    (define-key map [(control ?c) (control ?D)]
+                                          'emacs-wiki-delete-link-at-point)
+
+    (define-key map [(control ?c) (control ?l)] 'font-lock-mode)
+
+    (define-key map [(control ?c) ?=]
+      (lambda ()
+       (interactive)
+       (diff-backup buffer-file-name)))
+
+    (define-key map [tab] 'emacs-wiki-next-reference)
+    (define-key map [(control ?i)] 'emacs-wiki-next-reference)
+
+    (if (featurep 'xemacs)
+       (define-key map [(shift tab)] 'emacs-wiki-previous-reference)
+      (define-key map [(shift iso-lefttab)] 'emacs-wiki-previous-reference)
+      (define-key map [(shift control ?i)] 'emacs-wiki-previous-reference))
+
+    (when (featurep 'pcomplete)
+      (define-key map [(meta tab)] 'pcomplete)
+      (define-key map [(meta control ?i)] 'pcomplete))
+
+    map)
+  "Keymap used by Emacs Wiki mode.")
+
+(defvar emacs-wiki-local-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map [return] 'emacs-wiki-follow-name-at-point)
+    (define-key map [(control ?m)] 'emacs-wiki-follow-name-at-point)
+    (if (featurep 'xemacs)
+       (define-key map [(button2)] 'emacs-wiki-follow-name-at-mouse)
+      (define-key map [mouse-2] 'emacs-wiki-follow-name-at-mouse)
+      (unless (eq emacs-major-version 21)
+       (set-keymap-parent map emacs-wiki-mode-map)))
+    map)
+  "Local keymap used by emacs-wiki while on a WikiName.")
+
+;; Code:
+
+(defvar emacs-wiki-project nil)
+
+;;;###autoload
+(define-derived-mode emacs-wiki-mode text-mode "Wiki"
+  "An Emacs mode for maintaining a local Wiki database.
+
+Wiki is a hypertext and a content management system: Normal users are
+encouraged to enhance the hypertext by editing and refactoring existing
+wikis and by adding more.  This is made easy by requiring a certain way
+of writing the wikis.  It is not as complicated as a markup language
+such as HTML.  The general idea is to write plain ASCII.
+
+Words with mixed case such as ThisOne are WikiNames.  WikiNames are
+links you can follow.  If a wiki with that name exists, you will be
+taken there.  If such a does not exist, following the link will create
+a new wiki for you to fill.  WikiNames for non-existing wikis are
+rendered as links with class \"nonexistent\", and are also displayed
+in a warning color so that you can see wether following the link will
+lead you anywhere or not.
+
+In order to follow a link, hit RET when point is on the link, or use
+mouse-2.
+
+All wikis reside in the `emacs-wiki-directories'.
+
+\\{emacs-wiki-mode-map}"
+  (if emacs-wiki-project
+      (emacs-wiki-change-project emacs-wiki-project))
+  ;; because we're not inheriting from normal-mode, we need to
+  ;; explicitly run file variables if the user wants to
+  (condition-case err
+      (hack-local-variables)
+    (error (message "File local-variables error: %s"
+                   (prin1-to-string err))))
+  ;; bootstrap the file-alist, if it's not been read in yet
+  (emacs-wiki-file-alist t)
+  ;; if pcomplete is available, set it up!
+  (when (featurep 'pcomplete)
+    (set (make-variable-buffer-local 'pcomplete-default-completion-function)
+        'emacs-wiki-completions)
+    (set (make-variable-buffer-local 'pcomplete-command-completion-function)
+        'emacs-wiki-completions)
+    (set (make-variable-buffer-local 'pcomplete-parse-arguments-function)
+        'emacs-wiki-current-word)))
+
+(defsubst emacs-wiki-page-file (page &optional no-check-p)
+  "Return a filename if PAGE exists within the current Wiki."
+  (cdr (assoc page (emacs-wiki-file-alist no-check-p))))
+
+(defsubst emacs-wiki-directory-part (path)
+  (directory-file-name (expand-file-name path)))
+
+(defun emacs-wiki-directories-member (&optional directories)
+  "Return non-nil if the current buffer is in `emacs-wiki-directories'."
+  (let ((here (emacs-wiki-directory-part default-directory))
+       (d (or directories emacs-wiki-directories))
+       yes)
+    (while d
+      (if (string= here (emacs-wiki-directory-part (if (consp (car d))
+                                                      (caar d)
+                                                    (car d))))
+         (setq yes (car d) d nil)
+       (setq d (cdr d))))
+    yes))
+
+(defun emacs-wiki-maybe (&optional check-only)
+  "Maybe turn Emacs Wiki mode on for this file."
+  (let ((projs emacs-wiki-projects)
+       (mode-func 'emacs-wiki-mode)
+       project yes)
+    (while (and (not yes) projs)
+      (let* ((projsyms (cdar projs))
+            (pred (assq 'emacs-wiki-predicate projsyms))
+            dirs)
+       (if pred
+           (setq yes (funcall (cdr pred)))
+         (setq dirs (assq 'emacs-wiki-directories projsyms))
+         (if dirs
+             (setq yes (emacs-wiki-directories-member (cdr dirs)))))
+       (if yes
+           (setq project (caar projs)
+                 mode-func (or (cdr (assq 'emacs-wiki-major-mode projsyms))
+                               mode-func))))
+      (setq projs (cdr projs)))
+    (setq yes (or yes (emacs-wiki-directories-member)))
+    (if (and yes (not check-only))
+       (let ((emacs-wiki-project project))
+         (funcall mode-func)))
+    yes))
+
+(add-hook 'find-file-hooks 'emacs-wiki-maybe)
+
+;;; Support WikiName completion using pcomplete
+
+(defun emacs-wiki-completions ()
+  "Return a list of possible completions names for this buffer."
+  (while (pcomplete-here
+         (mapcar 'car (append (emacs-wiki-file-alist)
+                              emacs-wiki-interwiki-names)))))
+
+(defun emacs-wiki-current-word ()
+  (let ((end (point)))
+    (save-restriction
+      (save-excursion
+       (skip-chars-backward "^\\[ \t\n")
+       (narrow-to-region (point) end))
+      (pcomplete-parse-buffer-arguments))))
+
+;;; Return an list of known wiki names and the files they represent.
+
+(defsubst emacs-wiki-time-less-p (t1 t2)
+  "Say whether time T1 is less than time T2."
+  (or (< (car t1) (car t2))
+      (and (= (car t1) (car t2))
+          (< (nth 1 t1) (nth 1 t2)))))
+
+(defun emacs-wiki-page-name (&optional name)
+  "Return the canonical form of the Wiki page name.
+All this means is that certain extensions, like .gz, are removed."
+  (save-match-data
+    (unless name
+      (setq name buffer-file-name))
+    (if name
+        (let ((page (file-name-nondirectory name)))
+          (if (string-match emacs-wiki-ignored-extensions-regexp page)
+              (replace-match "" t t page)
+            page)))))
+
+(defun emacs-wiki-page-title (&optional name)
+  "Return the canonical form of the Wiki page name.
+All this means is that certain extensions, like .gz, are removed."
+  (or emacs-wiki-current-page-title
+      (emacs-wiki-prettify-title (emacs-wiki-page-name name))))
+
+(defvar emacs-wiki-file-alist nil)
+
+(defun emacs-wiki-file-alist (&optional no-check-p)
+  "Return possible Wiki filenames in `emacs-wiki-directories'.
+On UNIX, this list is only updated if one of the directories' contents
+have changed.  On Windows, it is always reread from disk."
+  (let* ((file-alist (assoc emacs-wiki-current-project
+                           emacs-wiki-file-alist))
+        (dirs emacs-wiki-directories)
+        (d dirs) last-mod)
+    (unless (or emacs-wiki-under-windows-p no-check-p)
+      (while d
+       (let ((mod-time (nth 5 (file-attributes (car d)))))
+         (if (or (null last-mod)
+                 (and mod-time (emacs-wiki-time-less-p last-mod mod-time)))
+             (setq last-mod mod-time)))
+       (setq d (cdr d))))
+    (if (or (and no-check-p (cadr file-alist))
+           (not (or emacs-wiki-under-windows-p
+                    (null (cddr file-alist))
+                    (null last-mod)
+                    (emacs-wiki-time-less-p (cddr file-alist) last-mod))))
+       (cadr file-alist)
+      (if file-alist
+         (setcdr (cdr file-alist) last-mod)
+       (setq file-alist (cons emacs-wiki-current-project (cons nil last-mod))
+             emacs-wiki-file-alist (cons file-alist emacs-wiki-file-alist)))
+      (save-match-data
+       (setcar
+        (cdr file-alist)
+        (let* ((names (list t))
+               (lnames names))
+          (while dirs
+            (if (file-readable-p (car dirs))
+                (let ((files (directory-files (car dirs) t nil t)))
+                  (while files
+                    (unless
+                        (or (file-directory-p (car files))
+                            (string-match emacs-wiki-file-ignore-regexp
+                                          (file-name-nondirectory
+                                           (car files))))
+                      (setcdr lnames
+                              (cons (cons (emacs-wiki-page-name (car files))
+                                          (car files)) nil))
+                      (setq lnames (cdr lnames)))
+                    (setq files (cdr files)))))
+            (setq dirs (cdr dirs)))
+          (cdr names)))))))
+
+(defun emacs-wiki-complete-alist ()
+  "Return equivalent of calling (emacs-wiki-file-alist) for all projects."
+  (let ((emacs-wiki-current-project "_CompositeFileList")
+       (emacs-wiki-directories
+        (copy-alist emacs-wiki-directories))
+       (projs emacs-wiki-projects))
+    (while projs
+      (let* ((projsyms (cdar projs))
+            (dirs (cdr (assq 'emacs-wiki-directories projsyms))))
+       (while dirs
+         (add-to-list 'emacs-wiki-directories (car dirs))
+         (setq dirs (cdr dirs))))
+      (setq projs (cdr projs)))
+    (emacs-wiki-file-alist)))
+
+;; Utility functions to extract parts of a Wiki name
+
+(defvar emacs-wiki-serving-p nil
+  "Non-nil when emacs-wiki is serving a wiki page directly.")
+
+(defsubst emacs-wiki-transform-name (name)
+  "Transform NAME as per `emacs-wiki-publishing-transforms', returning NAME"
+  (save-match-data
+    (mapc (function
+           (lambda (elt)
+             (let ((reg (car elt))
+                   (rep (cdr elt)))
+               (when (string-match reg name)
+                 (setq name (replace-match rep t nil name))))))
+          emacs-wiki-publishing-transforms)
+    name))
+
+(defsubst emacs-wiki-published-name (name &optional current)
+  "Return the externally visible NAME for a wiki page, possibly transformed
+  via `emacs-wiki-publishing-transforms'. If CURRENT is provided, convert any
+  path to be relative to it"
+  (emacs-wiki-transform-name
+   (progn
+     (when current
+       (setq name (file-relative-name name
+                                      (file-name-directory
+                                       (emacs-wiki-transform-name current)))))
+     (concat (if emacs-wiki-serving-p
+                 (unless (string-match "\\?" name) "wiki?")
+               emacs-wiki-publishing-file-prefix)
+             name
+             (if emacs-wiki-serving-p
+                 (if emacs-wiki-current-project
+                     (concat "&project=" emacs-wiki-current-project))
+               emacs-wiki-publishing-file-suffix)))))
+
+(defsubst emacs-wiki-published-file (&optional file)
+  "Return the filename of the published file. Since this is based on the
+  published-name, it will be filtered through
+  `emacs-wiki-publishing-transforms'"
+  (expand-file-name (emacs-wiki-published-name (emacs-wiki-page-name
+                                                file))
+                    emacs-wiki-publishing-directory))
+
+(defcustom emacs-wiki-publishing-transforms nil
+  "A list of cons cells mapping regexps to replacements, which is applied when
+generating the published name from the wiki file name. The replacements
+run in order so you can chain them together.
+
+An example is how I publish the emacs-wiki documentation. The emacs-wiki
+homepage is in a file called EmacsWiki. With the following settings I can
+publish directly to my webserver via tramp (the first rule catches 'WikiMarkup'
+for instance):
+
+(setq emacs-wiki-publishing-directory \"/webserver:/var/www/\")
+(setq emacs-wiki-publishing-transforms
+        ((\".*Wiki.*\" . \"emacs/wiki/\\&\")
+         (\"EmacsWiki\\|WelcomePage\" . \"index\")))
+
+Then when trying to publish a page EmacsWiki:
+
+(emacs-wiki-published-file \"EmacsWiki\")
+
+You get:
+
+\"/webserver:/var/www/emacs/wiki/index.html\""
+  :type '(repeat
+         (cons
+          (regexp :tag "String to match")
+          (string :tag "Replacement string")))
+  :group 'emacs-wiki-publish)
+
+(defsubst emacs-wiki-wiki-url-p (name)
+  "Return non-nil if NAME is a URL."
+  (save-match-data
+    (string-match emacs-wiki-url-regexp name)))
+
+(defun emacs-wiki-wiki-visible-name (wiki-name)
+  "Return the visible part of a Wiki link.
+This only really means something if [[extended][links]] are involved."
+  (save-match-data
+    (let ((name wiki-name))
+      (if (string-match emacs-wiki-extended-link-regexp name)
+         (if (match-string 2 name)
+             (setq name (match-string 3 name))
+           (setq name (match-string 1 name))))
+      (if (and (not (emacs-wiki-wiki-url-p name))
+              (string-match "#" name))
+         (if (= 0 (match-beginning 0))
+             (setq name (emacs-wiki-page-name))
+           (let ((base (substring name 0 (match-beginning 0))))
+             (if (assoc base emacs-wiki-interwiki-names)
+                 (setq name (concat (substring name 0 (match-beginning 0))
+                                    ":" (substring name (match-end 0))))
+               (setq name base)))))
+      name)))
+
+(defun emacs-wiki-wiki-tag (wiki-name)
+  (save-match-data
+    (if (string-match "#" wiki-name)
+       (substring wiki-name (match-end 0)))))
+
+(defun emacs-wiki-wiki-link-target (wiki-name)
+  "Return the target of a Wiki link.  This might include anchor tags."
+  (save-match-data
+    (let ((name wiki-name) lookup)
+      (if (string-match "^\\[\\[\\([^]]+\\)\\]" name)
+         (setq name (match-string 1 name)))
+      (if (and emacs-wiki-interwiki-names
+              (string-match "\\`\\([^#]+\\)\\(#\\(.+\\)\\)?\\'" name)
+              (setq lookup (assoc (match-string 1 name)
+                                  emacs-wiki-interwiki-names)))
+         (let ((tag (match-string 3 name))
+               (target (cdr lookup)))
+           (if (stringp target)
+               (setq name (concat target tag))
+             (setq name (funcall target tag))))
+       (if (and (> (length name) 0)
+                (eq (aref name 0) ?#))
+           (setq name (concat (emacs-wiki-page-name) name))))
+      name)))
+
+(defun emacs-wiki-wiki-base (wiki-name)
+  "Find the WikiName or URL mentioned by a Wiki link.
+This means without tags, in the case of a WikiName."
+  (save-match-data
+    (let ((file (emacs-wiki-wiki-link-target wiki-name)))
+      (if (emacs-wiki-wiki-url-p file)
+         file
+       (if (string-match "#" file)
+           (substring file 0 (match-beginning 0))
+         file)))))
+
+;;; Open a Wiki page (with completion)
+
+(defvar emacs-wiki-history-list nil)
+
+(defun emacs-wiki-read-name (file-alist &optional prompt)
+  "Read the name of a valid Wiki page from minibuffer, with completion."
+  (let* ((default emacs-wiki-default-page)
+        (str (completing-read
+              (format "%s(default: %s) " (or prompt "Wiki page: ") default)
+              file-alist nil nil nil 'emacs-wiki-history-list)))
+       (if (or (null str) (= (length str) 0))
+           default
+         str)))
+
+;;;###autoload
+(defun emacs-wiki-find-file (wiki &optional command directory)
+  "Open the Emacs Wiki page WIKI by name.
+If COMMAND is non-nil, it is the function used to visit the file.
+If DIRECTORY is non-nil, it is the directory in which the Wiki page
+will be created if it does not already exist."
+  (interactive
+   (list
+    (let ((num (prefix-numeric-value current-prefix-arg)))
+       (if (< num 16)
+          (let* ((file-alist (if (= num 4)
+                                 (emacs-wiki-complete-alist)
+                               (emacs-wiki-file-alist)))
+                 (name (emacs-wiki-read-name file-alist)))
+            (cons name (cdr (assoc name file-alist))))
+        (let ((name (read-file-name "Open wiki file: ")))
+          (cons name name))))))
+  (unless (interactive-p)
+    (setq wiki (cons wiki
+                    (cdr (assoc wiki (emacs-wiki-file-alist))))))
+  ;; At this point, `wiki' is (GIVEN-PAGE FOUND-FILE).
+  (if (cdr wiki)
+      (let ((buffer (funcall (or command 'find-file) (cdr wiki))))
+       (if (= (prefix-numeric-value current-prefix-arg) 16)
+           (with-current-buffer buffer
+             (set (make-variable-buffer-local 'emacs-wiki-directories)
+                  (cons (file-name-directory (cdr wiki))
+                        emacs-wiki-directories))
+             (set (make-variable-buffer-local 'emacs-wiki-file-alist) nil)))
+       buffer)
+    (let* ((dirname (or directory
+                       (emacs-wiki-maybe t)
+                       (car emacs-wiki-directories)))
+          (filename (expand-file-name (car wiki) dirname)))
+      (unless (file-exists-p dirname)
+       (make-directory dirname t))
+      (funcall (or command 'find-file) filename))))
+
+;;; Navigate/visit links or URLs.  Use TAB, S-TAB and RET (or mouse-2).
+
+(defun emacs-wiki-next-reference ()
+  "Move forward to next Wiki link or URL, cycling if necessary."
+  (interactive)
+  (let ((case-fold-search nil)
+       (cycled 0) pos)
+    (save-excursion
+      (if (emacs-wiki-link-at-point)
+         (goto-char (match-end 0)))
+      (while (< cycled 2)
+       (if (re-search-forward emacs-wiki-url-or-name-regexp nil t)
+           (setq pos (match-beginning 0)
+                 cycled 2)
+         (goto-char (point-min))
+         (setq cycled (1+ cycled)))))
+    (if pos
+       (goto-char pos))))
+
+(defun emacs-wiki-previous-reference ()
+  "Move backward to the next Wiki link or URL, cycling if necessary.
+This function is not entirely accurate, but it's close enough."
+  (interactive)
+  (let ((case-fold-search nil)
+       (cycled 0) pos)
+    (save-excursion
+      (while (< cycled 2)
+       (if (re-search-backward emacs-wiki-url-or-name-regexp nil t)
+           (setq pos (point)
+                 cycled 2)
+         (goto-char (point-max))
+         (setq cycled (1+ cycled)))))
+    (if pos
+       (goto-char pos))))
+
+(defun emacs-wiki-visit-link (link-name)
+  "Visit the URL or link named by LINK-NAME."
+  (let ((link (emacs-wiki-wiki-link-target link-name)))
+    (if (emacs-wiki-wiki-url-p link)
+       (funcall emacs-wiki-browse-url-function link)
+      ;; The name list is current since the last time the buffer was
+      ;; highlighted
+      (let* ((base (emacs-wiki-wiki-base link-name))
+            (file (emacs-wiki-page-file base t))
+            (tag  (and (not (emacs-wiki-wiki-url-p link))
+                       (emacs-wiki-wiki-tag link))))
+       (if (null file)
+           (find-file base)
+         (find-file file)
+         (when tag
+           (goto-char (point-min))
+           (re-search-forward (concat "^\\.?#" tag) nil t)))))))
+
+(unless (fboundp 'line-end-position)
+  (defsubst line-end-position (&optional N)
+    (save-excursion (end-of-line N) (point))))
+
+(unless (fboundp 'line-beginning-position)
+  (defsubst line-beginning-position (&optional N)
+    (save-excursion (beginning-of-line N) (point))))
+
+(unless (fboundp 'match-string-no-properties)
+  (defalias 'match-string-no-properties 'match-string))
+
+(defun emacs-wiki-link-at-point (&optional pos)
+  "Return non-nil if a URL or Wiki link name is at point."
+  (if (or (null pos)
+         (and (char-after pos)
+              (not (eq (char-syntax (char-after pos)) ? ))))
+      (let ((case-fold-search nil)
+           (here (or pos (point))))
+       (save-excursion
+         (goto-char here)
+         (skip-chars-backward "^'\"<>{}( \t\n")
+         (or (looking-at emacs-wiki-url-or-name-regexp)
+             (and (search-backward "[[" (line-beginning-position) t)
+                  (looking-at emacs-wiki-name-regexp)
+                  (<= here (match-end 0))))))))
+
+(defun emacs-wiki-follow-name-at-point ()
+  "Visit the link at point, or insert a newline if none."
+  (interactive)
+  (if (emacs-wiki-link-at-point)
+      (emacs-wiki-visit-link (match-string 0))
+    (error "There is no valid link at point")))
+
+(defun emacs-wiki-follow-name-at-mouse (event)
+  "Visit the link at point, or yank text if none."
+  (interactive "e")
+  (save-excursion
+    (cond ((fboundp 'event-window)     ; XEmacs
+          (set-buffer (window-buffer (event-window event)))
+          (and (event-point event) (goto-char (event-point event))))
+         ((fboundp 'posn-window)       ; Emacs
+          (set-buffer (window-buffer (posn-window (event-start event))))
+          (goto-char (posn-point (event-start event)))))
+    (if (emacs-wiki-link-at-point)
+       (emacs-wiki-visit-link (match-string 0)))))
+
+(defun emacs-wiki-rename-link (link-name new-name)
+  (when (emacs-wiki-wiki-url-p link-name)
+    (error "Can't rename a URL"))
+  (let* ((base (emacs-wiki-wiki-base link-name))
+         (file (emacs-wiki-page-file base t)))
+    (if (null file)
+        (rename-file base new-name)
+      (rename-file file new-name))))
+
+(defun emacs-wiki-rename-link-at-point ()
+  "Rename the link under point, and the location it points to. This does not
+  work with URLs"
+  (interactive "*")
+  (let (new-name old-name)
+    (if (emacs-wiki-link-at-point)
+        (progn
+          (setq old-name (match-string 0))
+          ;; emacs21 leaves the local keymap on this string, so we must strip
+          ;; properties so the user can hit return to exit minibuf
+          (set-text-properties 0 (length old-name) nil old-name)
+          (setq new-name (read-from-minibuffer "Rename to: " old-name))
+          (emacs-wiki-rename-link old-name new-name)
+          ;; at this point, the file would have been successfully renamed, so
+          ;; it's safe to change to link name now
+          (replace-match new-name nil t))
+      (error "There is no valid link at point"))))
+
+(defun emacs-wiki-delete-link (link-name)
+  "Delete the file which link-name corresponds to"
+  (when (emacs-wiki-wiki-url-p link-name)
+    (error "Can't rename a URL"))
+  (let* ((base (emacs-wiki-wiki-base link-name))
+         (file (emacs-wiki-page-file base t)))
+    (if (null file)
+        (delete-file base)
+      (delete-file file))))
+
+(defun emacs-wiki-delete-link-at-point ()
+  "Delete the link under point, and the location it points to. This does not
+  work with URLs"
+  (interactive "*")
+  (let (name)
+    (if (emacs-wiki-link-at-point)
+        (progn
+          (setq name (match-string 0))
+          (when (yes-or-no-p (concat "Delete "
+                                     name "? You can not undo this. "))
+            (emacs-wiki-delete-link name)
+            (replace-match "" nil t)))
+      (error "There is no valid link at point"))))
+
+;;; Find text in Wiki pages, or pages referring to the current page
+
+(defvar emacs-wiki-search-history nil)
+
+(defun emacs-wiki-grep (string &optional grep-command)
+  "Grep for STRING in the Wiki directories. GREP-COMMAND if passed will
+  supplant emacs-wiki-grep-command."
+  (require 'compile)
+  (let ((str (or grep-command emacs-wiki-grep-command))
+       (dirs (mapconcat (lambda (dir)
+                           (shell-quote-argument (expand-file-name dir)))
+                        emacs-wiki-directories " ")))
+    (while (string-match "%W" str)
+      (setq str (replace-match string t t str)))
+    (while (string-match "%D" str)
+      (setq str (replace-match dirs t t str)))
+    (compile-internal str "No more search hits" "search"
+                     nil grep-regexp-alist)))
+
+(defun emacs-wiki-search (text)
+  "Search for the given TEXT string in the Wiki directories."
+  (interactive
+   (list (let ((str (concat emacs-wiki-grep-command)) pos)
+          (when (string-match "%W" str)
+             (setq pos (match-beginning 0))
+             (unless (featurep 'xemacs)
+               (setq pos (1+ pos)))
+            (setq str (replace-match "" t t str)))
+          (read-from-minibuffer "Search command: "
+                                (cons str pos)
+                                nil nil 'emacs-wiki-search-history))))
+  (emacs-wiki-grep nil text))
+
+(defun emacs-wiki-backlink ()
+  "Grep for the current pagename in all the Wiki directories."
+  (interactive)
+  (emacs-wiki-grep (emacs-wiki-page-name)))
+
+;;; Generate an index of all known Wiki pages
+
+(defun emacs-wiki-generate-index (&optional as-list exclude-private)
+  "Generate an index of all Wiki pages."
+  (let ((project emacs-wiki-current-project))
+    (with-current-buffer (get-buffer-create "*Wiki Index*")
+      (erase-buffer)
+      (if project
+         (emacs-wiki-change-project project))
+      (let ((files (sort (copy-alist (emacs-wiki-file-alist))
+                        (function
+                         (lambda (l r)
+                           (string-lessp (car l) (car r))))))
+           file)
+       (while files
+         (unless (and exclude-private
+                      (emacs-wiki-private-p (caar files)))
+           (insert (if as-list "- " "") "[[" (caar files) "]]\n"))
+         (setq files (cdr files))))
+      (current-buffer))))
+
+(defun emacs-wiki-index ()
+  "Display an index of all known Wiki pages."
+  (interactive)
+  (message "Generating Wiki index...")
+  (pop-to-buffer (emacs-wiki-generate-index))
+  (goto-char (point-min))
+  (emacs-wiki-mode)
+  (message "Generating Wiki index...done"))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Emacs Wiki Highlighting
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defgroup emacs-wiki-highlight nil
+  "Options controlling the behaviour of Emacs Wiki highlighting.
+See `emacs-wiki-highlight-buffer' for more information."
+  :group 'emacs-wiki)
+
+(defun emacs-wiki-make-faces ()
+  (mapc (lambda (newsym)
+          (let (num)
+            (setq num newsym)
+            (setq newsym (intern (concat "emacs-wiki-header-"
+                                         (int-to-string num))))
+           (cond
+            ((featurep 'xemacs)
+              (eval `(defface ,newsym
+                       '((t (:size
+                             ,(nth (1- num) '("24pt" "18pt" "14pt" "12pt"))
+                             :bold t)))
+                       "emacs-wiki header face"
+                       :group 'emacs-wiki-highlight)))
+            ((< emacs-major-version 21)
+             (copy-face 'default newsym))
+            (t
+             (eval `(defface ,newsym
+                      '((t (:height ,(1+ (* 0.1 (- 5 num)))
+                                    :inherit variable-pitch
+                                    :weight bold)))
+                      "emacs-wiki header face"
+                      :group 'emacs-wiki-highlight))))))
+       '(1 2 3 4 5 6)))
+(emacs-wiki-make-faces)
+
+(defface emacs-wiki-link-face
+  '((((class color) (background light))
+     (:foreground "green" :underline "green" :bold t))
+    (((class color) (background dark))
+     (:foreground "cyan" :underline "cyan" :bold t))
+    (t (:bold t)))
+  "Face for Wiki cross-references."
+  :group 'emacs-wiki-highlight)
+
+(defface emacs-wiki-bad-link-face
+  '((((class color) (background light))
+     (:foreground "red" :underline "red" :bold t))
+    (((class color) (background dark))
+     (:foreground "coral" :underline "coral" :bold t))
+    (t (:bold t)))
+  "Face for bad Wiki cross-references."
+  :group 'emacs-wiki-highlight)
+
+(defcustom emacs-wiki-highlight-buffer-hook nil
+  "A hook run after a region is highlighted.
+Each function receives three arguments: BEG END VERBOSE.
+BEG and END mark the range being highlighted, and VERBOSE specifies
+whether progress messages should be displayed to the user."
+  :type 'hook
+  :group 'emacs-wiki-highlight)
+
+(defcustom emacs-wiki-inline-images (and (not (featurep 'xemacs))
+                                        (>= emacs-major-version 21)
+                                        window-system)
+  "If non-nil, inline locally available images within Wiki pages."
+  :type 'boolean
+  :group 'emacs-wiki-highlight)
+
+(defcustom emacs-wiki-image-regexp
+  "\\.\\(eps\\|gif\\|jp\\(e?g\\)\\|p\\(bm\\|ng\\)\\|tiff\\|x\\([bp]m\\)\\)\\'"
+  "A link matching this regexp will be published inline as an image. Remember
+that it must be matched as a link first - so use either [[CamelCaps]] or
+include a leading slash - [[./text]]. An example:
+
+  [[./wife.jpg][A picture of my wife]]
+
+If you omit the description, the alt tag of the resulting HTML buffer will be
+the name of the file."
+  :type 'regexp
+  :group 'emacs-wiki)
+
+(defcustom emacs-wiki-file-regexp
+  "[/?]\\|\\.\\(html?\\|pdf\\|el\\|zip\\|txt\\|tar\\)\\(\\.\\(gz\\|bz2\\)\\)?\\'"
+  "A link matching this regexp will be regarded as a link to a file. Remember
+that it must be matched as a link first - so use either [[CamelCaps]] or
+include a leading slash - [[./text]]"
+  :type 'regexp
+  :group 'emacs-wiki)
+
+(defcustom emacs-wiki-tag-regexp
+  "<\\([^/ \t\n][^ \t\n</>]*\\)\\(\\s-+[^<>]+[^</>]\\)?\\(/\\)?>"
+  "A regexp used to find XML-style tags within a buffer when publishing.
+Group 1 should be the tag name, group 2 the properties, and group
+3 the optional immediate ending slash."
+  :type 'regexp
+  :group 'emacs-wiki)
+
+(defcustom emacs-wiki-inline-relative-to 'emacs-wiki-publishing-directory
+  "The name of a symbol which records the location relative to where images
+  should be found. The default assumes that when editing, the images can be
+  found in the publishing directory. Another sensible default is
+  `default-directory', which will try and find the images relative to the
+  local page. You can use this to store images in wikidir/images, and
+  maintain a parallel copy on the remote host."
+  :type 'symbol
+  :group 'emacs-wiki)
+
+(defcustom emacs-wiki-markup-tags
+  '(("example" t nil t emacs-wiki-example-tag)
+    ("verbatim" t nil t emacs-wiki-verbatim-tag)
+    ("nowiki" t nil t emacs-wiki-nowiki-tag)
+    ("verse" t nil nil emacs-wiki-verse-tag)
+    ("numbered" t nil nil emacs-wiki-numbered-tag)
+    ("nop" nil nil t emacs-wiki-nop-tag)
+    ("contents" nil t nil emacs-wiki-contents-tag)
+    ("c-source" t t t emacs-wiki-c-source-tag))
+  "A list of tag specifications, for specially marking up Wiki text.
+XML-style tags are the best way to add custom markup to Emacs Wiki.
+This is easily accomplished by customizing this list of markup tags.
+
+For each entry, the name of the tag is given, whether it expects a
+closing tag and/or an optional set of attributes, if the handler
+function can also highlight the tag, and a function that performs
+whatever action is desired within the delimited region.
+
+The tags themselves are deleted during publishing, although not during
+highlighting, before the function is called.  The function is called
+with three arguments, the beginning and end of the region surrounded
+by the tags (including the tags themselves, in the case of
+highlighting).  The third argument indicates whether the purpose of
+the call is to highlight the region, or mark it up for publishing.  If
+properties are allowed, they are passed as a fourth argument in the
+form of an alist.  The `end' argument to the function is always a
+marker.
+
+Point is always at the beginning of the region within the tags, when
+the function is called.  Wherever point is when the function finishes
+is where tag markup/highlighting will resume.
+
+These tag rules are processed once at the beginning of markup, and
+once at the end, to catch any tags which may have been inserted
+in-between.  For highlighting, they are processed as they occur, in
+the order they occur, once per text region.
+
+Here is a summary of the default tags.  This includes the dangerous
+tags listed in `emacs-wiki-dangerous-tags', which may not be used by
+outsiders.
+
+ verbatim
+   Protects against highlighting and wiki interpretation, and escapes any
+   characters which have special meaning to the publishing format. For HTML,
+   this means characters like '<' are escaped as HTML entities.
+
+ example
+   Like verbatim, but typesets in HTML using the <pre> tag, with
+   class=example, so whitespace formatting is preserved.
+
+ nowiki
+   Inhibits wiki markup, but does not do any escaping to the underlying
+   publishing medium. Useful for embedding HTML, PHP, etc.
+
+ verse
+   Typesets like a normal paragraph, but without word-wrapping.
+   That is, whitespace is preserved.
+
+ redirect
+   Using the \"url\" attribute, you can specify that a page should
+   redirect to another page.  The remaining contents of the page will
+   not be published.  The optional \"delay\" attribute specifies how
+   long to wait before redirecting.
+
+ nop
+   When placed before a WikiLink, it will prevent that WikiLink from
+   being treated as such.  Good for names like DocBook.
+
+ contents
+   Produces a compact table of contents for any section heading at the
+   same level or lower than the next section header encountered.
+   Optional \"depth\" attribute specifies how deep the table of
+   contents should go.
+
+ lisp
+   Evaluate the region as a Lisp form, and displays the result.  When
+   highlighting, the `display' text property is used, preserving the
+   underlying text.  Turn off font-lock mode if you wish to edit it.
+
+ command
+   Pass the region to a command interpretor and insert the result,
+   guarding it from any further expansion.  Optional \"file\"
+   attribute specifies the shell or interpretor to use.  If none is
+   given, and `emacs-wiki-command-tag-file' has not been configured,
+   Eshell is used.
+
+ python, perl
+   Pass the region to the Python or Perl language interpretor, and
+   insert the result.
+
+ c-source
+   Markup the region as C or C++ source code, using the c2html
+   program, if available.  Optional boolean attribute \"numbered\"
+   will cause source lines to be numbered.
+
+   Note: If c2html is not available, the region will be converted to
+   HTML friendly text (i.e., <> turns into &lt;&gt;), and placed in a
+   <pre> block.  In this case, line numbering is not available.
+
+ bookmarks
+   Insert bookmarks at the location of the tag from the given
+   bookmarks file.  Required attribute \"file\" specifies which file
+   to read from, and the optional attribute \"type\" may be one of:
+   adr (for Opera), lynx, msie, ns, xbel or xmlproc.  The default type
+   is \"xbel\".  The optional attribute \"folder\" may be used to
+   specify which folder (and its children) should be inserted.
+
+   Note that xml-parse.el version 1.5 (available from my website) and
+   the xbel-utils package (available at least to Debian users) is
+   required for this feature to work."
+  :type '(repeat (list (string :tag "Markup tag")
+                      (boolean :tag "Expect closing tag" :value t)
+                      (boolean :tag "Parse attributes" :value nil)
+                      (boolean :tag "Highlight tag" :value nil)
+                      function))
+  :group 'emacs-wiki-highlight)
+
+(defcustom emacs-wiki-dangerous-tags
+  '(("redirect" t t nil emacs-wiki-redirect-tag)
+    ("lisp" t nil t emacs-wiki-lisp-tag)
+    ("command" t t t emacs-wiki-command-tag)
+    ("python" t t t emacs-wiki-python-tag)
+    ("perl" t t t emacs-wiki-perl-tag)
+    ("bookmarks" nil t nil emacs-wiki-bookmarks-tag))
+  "A list of tag specifications, for specially marking up Wiki text.
+These tags are dangerous -- meaning represent a gaping security hole
+-- and therefore are not available to outsiders who happen to edit a
+Wiki page"
+  :type '(repeat (list (string :tag "Markup tag")
+                      (boolean :tag "Expect closing tag" :value t)
+                      (boolean :tag "Parse attributes" :value nil)
+                      (boolean :tag "Highlight tag" :value nil)
+                      function))
+  :group 'emacs-wiki-highlight)
+
+(defvar emacs-wiki-highlight-regexp nil)
+(defvar emacs-wiki-highlight-vector nil)
+
+(defun emacs-wiki-configure-highlighting (sym val)
+  (setq emacs-wiki-highlight-regexp
+       (concat "\\(" (mapconcat (function
+                                 (lambda (rule)
+                                   (if (symbolp (car rule))
+                                       (symbol-value (car rule))
+                                     (car rule)))) val "\\|") "\\)")
+       emacs-wiki-highlight-vector (make-vector 128 nil))
+  (let ((rules val))
+    (while rules
+      (if (eq (cadr (car rules)) t)
+         (let ((i 0) (l 128))
+           (while (< i l)
+             (unless (aref emacs-wiki-highlight-vector i)
+               (aset emacs-wiki-highlight-vector i
+                     (nth 2 (car rules))))
+             (setq i (1+ i))))
+       (aset emacs-wiki-highlight-vector (cadr (car rules))
+             (nth 2 (car rules))))
+      (setq rules (cdr rules))))
+  (set sym val))
+
+(defsubst emacs-wiki-highlight-ok-context-p (beg end str)
+  "Ensures whitespace or punctuation comes before the position BEG, and
+  after the string STR. A search-forward is done for STR, bounding by END, and
+  the position of the end of the match is returned if in the correct context."
+  (save-excursion
+    (let ((len (length str)))
+      (and
+       (setq end (search-forward str end t))
+       ;; post end, want eob or whitespace/punctuation
+       (or (> (skip-syntax-forward ". " (1+ end)) 0)
+           (eq nil (char-after end)))
+       (goto-char (- end len))
+       ;; pre end, no whitespace
+       (eq (skip-syntax-backward " " (- end len 1)) 0)
+       (goto-char (+ beg len))
+       ;; post beg, no whitespace
+       (eq (skip-syntax-forward " " (+ beg len 1)) 0)
+       (or (backward-char len) t) ;; doesn't return anything useful
+       ;; pre beg, want sob or whitespace/punctuation
+       (or (< (skip-syntax-backward ". " (1- beg)) 0)
+           (eq nil (char-before beg)))
+       end))))
+
+(defun emacs-wiki-multiline-maybe (beg end &optional predicate)
+  "If region between beg-end is a multi-line region, and the optional
+  predicate is true, font lock the current region as multi-line. Predicate is
+  called with the excursion saved."
+  (when (and (or (eq (char-before end) ?\n)
+                 (> (count-lines beg end) 1))
+             (or (not predicate)
+                 (save-excursion (funcall predicate beg end))))
+    (save-excursion
+      ;; mark whole lines as a multiline font-lock
+      (goto-char beg)
+      (setq beg (line-beginning-position))
+      (goto-char end)
+      (setq end (line-end-position))
+      (add-text-properties beg end '(font-lock-multiline t))
+      t)))
+
+(defun emacs-wiki-highlight-emphasized ()
+  ;; here we need to check four different points - the start and end of the
+  ;; leading *s, and the start and end of the trailing *s. we allow the
+  ;; outsides to be surrounded by whitespace or punctuation, but no word
+  ;; characters, and the insides must not be surrounded by whitespace or
+  ;; punctuation. thus the following are valid:
+  ;; " *foo bar* "
+  ;; "**foo**,"
+  ;; and the following is invalid:
+  ;; "** testing **"
+  (let* ((beg (match-beginning 0))
+        (e1 (match-end 0))
+        (leader (- e1 beg))
+         (end end)
+        b2 e2 face)
+    ;; if it's a header
+    (unless (save-excursion
+              (goto-char beg)
+              (when (save-match-data (looking-at "^\\*\\{1,3\\} "))
+                (add-text-properties
+                 (line-beginning-position) (line-end-position)
+                 (list 'face
+                       (intern (concat "emacs-wiki-header-"
+                                       (int-to-string (1+ leader))))))
+                t))
+      ;; it might be an normal, emphasised piece of text
+      (when (and
+             (setq e2 (emacs-wiki-highlight-ok-context-p
+                       beg end (buffer-substring-no-properties beg e1)))
+             (setq b2 (match-beginning 0)))
+        (cond ((= leader 1) (setq face 'italic))
+              ((= leader 2) (setq face 'bold))
+              ((= leader 3) (setq face 'bold-italic)))
+        (add-text-properties beg e1 '(invisible t intangible t))
+        (add-text-properties e1 b2 (list 'face face))
+        (add-text-properties b2 e2 '(invisible t intangible t)))
+      (emacs-wiki-multiline-maybe
+       beg end
+       ;; ensures we only mark the region as multiline if it's correctly
+       ;; delimited at the start
+       (lambda (beg end)
+         (goto-char (1+ beg))
+         (eq (skip-syntax-forward " " (1+ beg)) 0)
+         (or (backward-char) t)
+         (or (< (skip-syntax-backward ". " (1- beg)) 0)
+             (eq nil (char-before beg))))))))
+
+(defun emacs-wiki-highlight-underlined ()
+  (let ((start (- (point) 2))
+        end)
+    (when (setq end (emacs-wiki-highlight-ok-context-p start end "_"))
+      (add-text-properties start (+ start 1) '(invisible t intangible t))
+      (add-text-properties (+ start 1) (- end 1) '(face underline))
+      (add-text-properties (- end 1) end '(invisible t intangible t)))))
+
+(defun emacs-wiki-highlight-verbatim ()
+  (let ((start (- (point) 2))
+        end)
+    (when (setq end (emacs-wiki-highlight-ok-context-p start end "="))
+        (search-forward "=" end t))))
+
+(defcustom emacs-wiki-highlight-markup
+  `(;; render in teletype and suppress further parsing
+    ("=[^\t =]" ?= emacs-wiki-highlight-verbatim)
+
+    ;; make emphasized text appear emphasized
+    ("\\*+" ?* emacs-wiki-highlight-emphasized)
+
+    ;; make underlined text appear underlined
+    ("_[^ \t_]" ?_ emacs-wiki-highlight-underlined)
+
+    ;; make quadruple quotes invisible
+    ("''''" ?\'
+     ,(function
+       (lambda ()
+        (add-text-properties (match-beginning 0) (match-end 0)
+                             '(invisible t intangible t)))))
+
+    ("^#title" ?\# emacs-wiki-highlight-title)
+
+    (emacs-wiki-url-or-name-regexp t emacs-wiki-highlight-link)
+
+    ;; highlight any markup tags encountered
+    (emacs-wiki-tag-regexp ?\< emacs-wiki-highlight-custom-tags))
+  "Expressions to highlight an Emacs Wiki buffer.
+These are arranged in a rather special fashion, so as to be as quick as
+possible.
+
+Each element of the list is itself a list, of the form:
+
+  (LOCATE-REGEXP TEST-CHAR MATCH-FUNCTION)
+
+LOCATE-REGEXP is a partial regexp, and should be the smallest possible
+regexp to differentiate this rule from other rules.  It may also be a
+symbol containing such a regexp.  The buffer region is scanned only
+once, and LOCATE-REGEXP indicates where the scanner should stop to
+look for highlighting possibilities.
+
+TEST-CHAR is a char or t.  The character should match the beginning
+text matched by LOCATE-REGEXP.  These chars are used to build a vector
+for fast MATCH-FUNCTION calling.
+
+MATCH-FUNCTION is the function called when a region has been
+identified.  It is responsible for adding the appropriate text
+properties to change the appearance of the buffer.
+
+This markup is used to modify the appearance of the original text to
+make it look more like the published HTML would look (like making some
+markup text invisible, inlining images, etc).
+
+font-lock is used to apply the markup rules, so that they can happen
+on a deferred basis.  They are not always accurate, but you can use
+\\[font-lock-fontifty-block] near the point of error to force
+fontification in that area.
+
+Lastly, none of the regexp should contain grouping elements that will
+affect the match data results."
+  :type '(repeat
+         (list :tag "Highlight rule"
+               (choice (regexp :tag "Locate regexp")
+                       (symbol :tag "Regexp symbol"))
+               (choice (character :tag "Confirm character")
+                       (const :tag "Default rule" t))
+               function))
+  :set 'emacs-wiki-configure-highlighting
+  :group 'emacs-wiki-highlight)
+
+(defvar font-lock-mode nil)
+(defvar font-lock-multiline nil)
+
+(defun emacs-wiki-use-font-lock ()
+  (set (make-local-variable 'font-lock-multiline) 'undecided)
+  (set (make-local-variable 'font-lock-defaults)
+       `(nil t nil nil 'beginning-of-line
+        (font-lock-fontify-region-function . emacs-wiki-highlight-region)
+        (font-lock-unfontify-region-function
+         . emacs-wiki-unhighlight-region)))
+  (set (make-local-variable 'font-lock-fontify-region-function)
+       'emacs-wiki-highlight-region)
+  (set (make-local-variable 'font-lock-unfontify-region-function)
+       'emacs-wiki-unhighlight-region)
+  (font-lock-mode t))
+
+(defun emacs-wiki-mode-flyspell-verify ()
+  "Return t if the word at point should be spell checked."
+  (let* ((word-pos (1- (point)))
+        (props (text-properties-at word-pos)))
+    (not (or (bobp)
+            (memq 'display props)
+            (if (and font-lock-mode (cadr (memq 'fontified props)))
+                (memq (cadr (memq 'face props))
+                      '(emacs-wiki-link-face emacs-wiki-bad-link-face))
+              (emacs-wiki-link-at-point word-pos))))))
+
+(put 'emacs-wiki-mode 'flyspell-mode-predicate
+     'emacs-wiki-mode-flyspell-verify)
+
+(defun emacs-wiki-eval-lisp (form)
+  "Evaluate the given form and return the result as a string."
+  (require 'pp)
+  (save-match-data
+    (let ((object (eval (read form))))
+      (cond
+       ((stringp object) object)
+       ((and (listp object)
+            (not (eq object nil)))
+       (let ((string (pp-to-string object)))
+         (substring string 0 (1- (length string)))))
+       ((numberp object)
+       (number-to-string object))
+       ((eq object nil) "")
+       (t
+       (pp-to-string object))))))
+
+(defun emacs-wiki-highlight-buffer ()
+  "Re-highlight the entire Wiki buffer."
+  (interactive)
+  (emacs-wiki-highlight-region (point-min) (point-max) t))
+
+(defun emacs-wiki-highlight-region (beg end &optional verbose)
+  "Apply highlighting according to `emacs-wiki-highlight-markup'.
+Note that this function should NOT change the buffer, nor should any
+of the functions listed in `emacs-wiki-highlight-markup'."
+  (let ((buffer-undo-list t)
+       (inhibit-read-only t)
+       (inhibit-point-motion-hooks t)
+       (inhibit-modification-hooks t)
+       (modified-p (buffer-modified-p))
+       deactivate-mark)
+    (unwind-protect
+       (save-excursion
+         (save-restriction
+           (widen)
+           ;; check to see if we should expand the beg/end area for
+           ;; proper multiline matches
+           (when (and font-lock-multiline
+                      (> beg (point-min))
+                      (get-text-property (1- beg) 'font-lock-multiline))
+             ;; We are just after or in a multiline match.
+             (setq beg (or (previous-single-property-change
+                            beg 'font-lock-multiline)
+                           (point-min)))
+             (goto-char beg)
+             (setq beg (line-beginning-position)))
+           (when font-lock-multiline
+             (setq end (or (text-property-any end (point-max)
+                                              'font-lock-multiline nil)
+                           (point-max))))
+           (goto-char end)
+           (setq end (line-beginning-position 2))
+           ;; Undo any fontification in the area.
+           (font-lock-unfontify-region beg end)
+           ;; And apply fontification based on `emacs-wiki-highlight-markup'
+           (let ((len (float (- end beg)))
+                 (case-fold-search nil))
+             (goto-char beg)
+             (while
+                 (and (< (point) end)
+                      (re-search-forward emacs-wiki-highlight-regexp end t))
+               (if verbose
+                   (message "Highlighting buffer...%d%%"
+                            (* (/ (float (- (point) beg)) len) 100)))
+               (funcall (aref emacs-wiki-highlight-vector
+                              (char-after (match-beginning 0)))))
+             (run-hook-with-args 'emacs-wiki-highlight-buffer-hook
+                                 beg end verbose)
+             (if verbose (message "Highlighting buffer...done")))))
+      (set-buffer-modified-p modified-p))))
+
+(defun emacs-wiki-unhighlight-region (begin end &optional verbose)
+  "Remove all visual highlights in the buffer (except font-lock)."
+  (let ((buffer-undo-list t)
+       (inhibit-read-only t)
+       (inhibit-point-motion-hooks t)
+       (inhibit-modification-hooks t)
+       (modified-p (buffer-modified-p))
+       deactivate-mark)
+    (unwind-protect
+       (remove-text-properties
+        begin end '(face nil font-lock-multiline nil
+                         invisible nil intangible nil display nil
+                         mouse-face nil keymap nil help-echo nil))
+      (set-buffer-modified-p modified-p))))
+
+(eval-when-compile
+  (defvar end))
+
+(defun emacs-wiki-multiline-maybe (beg end &optional predicate)
+  "If region between beg-end is a multi-line region, and the optional
+  predicate is true, font lock the current region as multi-line. Predicate is
+  called with the excursion saved."
+  (when (and (or (eq (char-before end) ?\n)
+                 (> (count-lines beg end) 1))
+             (or (not predicate)
+                 (save-excursion (funcall predicate beg end))))
+    (save-excursion
+      ;; mark whole lines as a multiline font-lock
+      (goto-char beg)
+      (setq beg (line-beginning-position))
+      (goto-char end)
+      (setq end (line-end-position))
+      (add-text-properties beg end '(font-lock-multiline t))
+      t)))
+
+(defvar emacs-wiki-keymap-property
+  (if (or (featurep 'xemacs)
+         (>= emacs-major-version 21))
+      'keymap
+    'local-map))
+
+(defsubst emacs-wiki-link-properties (help-str &optional face)
+  (append (if face
+             (list 'face face 'rear-nonsticky t
+                    emacs-wiki-keymap-property emacs-wiki-local-map)
+           (list 'invisible t 'intangible t 'rear-nonsticky t
+                  emacs-wiki-keymap-property emacs-wiki-local-map))
+         (list 'mouse-face 'highlight
+               'help-echo help-str
+               emacs-wiki-keymap-property emacs-wiki-local-map)))
+
+(defun emacs-wiki-highlight-link ()
+  (if (eq ?\[ (char-after (match-beginning 0)))
+      (if (and emacs-wiki-inline-images
+              (save-match-data
+                (string-match emacs-wiki-image-regexp (match-string 4))))
+         (emacs-wiki-inline-image (match-beginning 0) (match-end 0)
+                                  (match-string 4) (match-string 6))
+       (let* ((link (match-string-no-properties 4))
+              (invis-props (emacs-wiki-link-properties link))
+              (props (emacs-wiki-link-properties link 'emacs-wiki-link-face)))
+         (if (match-string 6)
+             (progn
+               (add-text-properties (match-beginning 0)
+                                    (match-beginning 6) invis-props)
+               (add-text-properties (match-beginning 6) (match-end 6) props)
+               (add-text-properties (match-end 6) (match-end 0) invis-props))
+           (add-text-properties (match-beginning 0)
+                                (match-beginning 4) invis-props)
+           (add-text-properties (match-beginning 4) (match-end 0) props)
+           (add-text-properties (match-end 4) (match-end 0) invis-props)))
+       (goto-char (match-end 0)))
+    (if (and emacs-wiki-inline-images
+            (save-match-data
+              (string-match emacs-wiki-image-regexp (match-string 0))))
+       (emacs-wiki-inline-image (match-beginning 0) (match-end 0)
+                                (match-string 0))
+      (add-text-properties
+       (match-beginning 0) (match-end 0)
+       (emacs-wiki-link-properties
+       (match-string-no-properties 0)
+       (if (let ((base (emacs-wiki-wiki-base (match-string 0))))
+             (or (emacs-wiki-page-file base t)
+                 (save-match-data
+                   (string-match "\\(/\\|\\`[a-z]\\{3,6\\}:\\)" base))))
+           'emacs-wiki-link-face
+         'emacs-wiki-bad-link-face)))
+      (goto-char (match-end 0)))))
+
+(defun emacs-wiki-inline-image (beg end url &optional desc)
+  "Inline locally available images."
+  (let ((filename
+        (cond
+         ((string-match "\\`file:\\(.+\\)" url)
+          (match-string 1 url))
+         ((string-match "/" url)
+          (expand-file-name url (symbol-value
+                                  emacs-wiki-inline-relative-to))))))
+    (if (and filename (file-readable-p filename))
+       (add-text-properties beg end (list 'display (create-image filename)
+                                          'help-echo (or desc url))))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Emacs Wiki Publishing (to HTML by default)
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defgroup emacs-wiki-publish nil
+  "Options controlling the behaviour of Emacs Wiki publishing.
+See `emacs-wiki-publish' for more information."
+  :group 'emacs-wiki)
+
+(defcustom emacs-wiki-maintainer (concat "mailto:webmaster@" (system-name))
+  "URL where the maintainer can be reached."
+  :type 'string
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-home-page emacs-wiki-default-page
+  "Title of the Wiki Home page."
+  :type 'string
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-index-page "WikiIndex"
+  "Title of the Wiki Index page."
+  :type 'string
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-downcase-title-words
+  '("the" "and" "at" "on" "of" "for" "in" "an" "a")
+  "Strings that should be downcased in a Wiki page title."
+  :type '(repeat string)
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-use-mode-flags (not emacs-wiki-under-windows-p)
+  "If non-nil, use file mode flags to determine page permissions.
+Otherwise the regexps in `emacs-wiki-private-pages' and
+`emacs-wiki-editable-pages' are used."
+  :type 'boolean
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-private-pages nil
+  "A list of regexps to exclude from public view.
+This variable only applies if `emacs-wiki-use-mode-flags' is nil."
+  :type '(choice (const nil) (repeat regexp))
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-editable-pages nil
+  "A list of regexps of pages that may be edited via HTTP.
+This variable only applies if `emacs-wiki-use-mode-flags' is nil."
+  :type '(choice (const nil) (repeat regexp))
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-publishing-directory "~/WebWiki"
+  "Directory where all wikis are published to."
+  :type 'directory
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-publishing-file-prefix ""
+  "This prefix will be prepended to all wiki names when publishing."
+  :type 'string
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-publishing-file-suffix ".html"
+  "This suffix will be appended to all wiki names when publishing."
+  :type 'string
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-before-markup-hook nil
+  "A hook run in the buffer where markup is done, before it is done."
+  :type 'hook
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-after-markup-hook nil
+  "A hook run in the buffer where markup is done, after it is done."
+  :type 'hook
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-meta-http-equiv "Content-Type"
+  "The http-equiv attribute used for the HTML <meta> tag."
+  :type 'string
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-meta-content-type "text/html"
+  "The content type used for the HTML <meta> tag."
+  :type 'string
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-meta-content-coding
+  (if (featurep 'mule)
+      'detect
+    "iso-8859-1")
+  "If set to the symbol 'detect, use `emacs-wiki-coding-map' to try
+  and determine the HTML charset from emacs's coding. If set to a string, this
+  string will be used to force a particular charset"
+  :type '(choice string symbol)
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-charset-default "iso-8859-1"
+  "The default HTML meta charset to use if no translation is found in
+  `emacs-wiki-coding-map'"
+  :type 'string
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-coding-default 'iso-8859-1
+  "The default emacs coding  use if no special characters are found"
+  :type 'symbol
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-coding-map
+  '((iso-2022-jp "iso-2022-jp")
+    (utf-8 "utf-8")
+    (japanese-iso-8bit "euc-jp"))
+  "An alist mapping emacs coding systems to appropriate HTML charsets.
+  Use the base name of the coding system (ie, without the -unix)"
+  :type '(alist :key-type coding-system :value-type (group string))
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-redirect-delay 1
+  "The number of seconds to delay before doing a page redirect."
+  :type 'integer
+  :group 'emacs-wiki-publish)
+
+(defvar emacs-wiki-current-page-title nil
+  "Current page title, used instead of buffer name if non-nil.
+This is usually set by code called by `emacs-wiki-publishing-markup'.
+It should never be changed globally.")
+
+(defcustom emacs-wiki-anchor-on-word nil
+  "When true, anchors surround the closest word. This allows you
+to select them in a browser (ie, for pasting), but has the
+side-effect of marking up headers in multiple colours if your
+header style is different to your link style."
+  :type 'boolean
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-publishing-header
+  "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">
+<html>
+  <head>
+    <title><lisp>(emacs-wiki-page-title)</lisp></title>
+    <meta name=\"generator\" content=\"emacs-wiki.el\">
+    <meta http-equiv=\"<lisp>emacs-wiki-meta-http-equiv</lisp>\"
+         content=\"<lisp>emacs-wiki-meta-content</lisp>\">
+    <link rev=\"made\" href=\"<lisp>emacs-wiki-maintainer</lisp>\">
+    <link rel=\"home\" href=\"<lisp>(emacs-wiki-published-name
+                                    emacs-wiki-home-page)</lisp>\">
+    <link rel=\"index\" href=\"<lisp>(emacs-wiki-published-name
+                                     emacs-wiki-index-page)</lisp>\">
+    <lisp>emacs-wiki-style-sheet</lisp>
+  </head>
+  <body>
+    <h1><lisp>(emacs-wiki-page-title)</lisp></h1>
+    <!-- Page published by Emacs Wiki begins here -->\n"
+  "Text to prepend to a wiki being published.
+This text may contain <lisp> markup tags."
+  :type 'string
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-publishing-footer
+  "
+    <!-- Page published by Emacs Wiki ends here -->
+    <div class=\"navfoot\">
+      <hr>
+      <table width=\"100%\" border=\"0\" summary=\"Footer navigation\">
+       <tr>
+         <td width=\"33%\" align=\"left\">
+           <lisp>
+             (if buffer-file-name
+                 (concat
+                  \"<span class=\\\"footdate\\\">Updated: \"
+                  (format-time-string emacs-wiki-footer-date-format
+                   (nth 5 (file-attributes buffer-file-name)))
+                  (and emacs-wiki-serving-p
+                       (emacs-wiki-editable-p (emacs-wiki-page-name))
+                       (concat
+                        \" / \"
+                        (emacs-wiki-link-href
+                         (concat \"editwiki?\" (emacs-wiki-page-name))
+                         \"Edit\")))
+                  \"</span>\"))
+           </lisp>
+         </td>
+         <td width=\"34%\" align=\"center\">
+           <span class=\"foothome\">
+             <lisp>
+               (concat
+                (and (emacs-wiki-page-file emacs-wiki-home-page t)
+                     (not (emacs-wiki-private-p emacs-wiki-home-page))
+                     (concat
+                      (emacs-wiki-link-href emacs-wiki-home-page \"Home\")
+                      \" / \"))
+                (emacs-wiki-link-href emacs-wiki-index-page \"Index\")
+                (and (emacs-wiki-page-file \"ChangeLog\" t)
+                     (not (emacs-wiki-private-p \"ChangeLog\"))
+                     (concat
+                      \" / \"
+                      (emacs-wiki-link-href \"ChangeLog\" \"Changes\"))))
+             </lisp>
+           </span>
+         </td>
+         <td width=\"33%\" align=\"right\">
+           <lisp>
+             (if emacs-wiki-serving-p
+                 (concat
+                  \"<span class=\\\"footfeed\\\">\"
+                  (emacs-wiki-link-href \"searchwiki?get\" \"Search\")
+                  (and buffer-file-name
+                       (concat
+                        \" / \"
+                        (emacs-wiki-link-href
+                         (concat \"searchwiki?q=\" (emacs-wiki-page-name))
+                         \"Referrers\")))
+                  \"</span>\"))
+           </lisp>
+         </td>
+       </tr>
+      </table>
+    </div>
+  </body>
+</html>\n"
+  "Text to append to a wiki being published.
+This text may contain <lisp> markup tags."
+  :type 'string
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-footer-date-format "%Y-%m-%d"
+  "Format of current date for `emacs-wiki-publishing-footer'.
+This string must be a valid argument to `format-time-string'."
+  :type 'string
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-style-sheet
+  "<style type=\"text/css\">
+a.nonexistent {
+  font-weight: bold;
+  background-color: #F8F8F8; color: #FF2222;
+}
+
+a.nonexistent:visited {
+  background-color: #F8F8F8; color: #FF2222;
+}
+
+body {
+  background: white; color: black;
+  margin-left: 5%; margin-right: 5%;
+  margin-top: 3%;
+}
+
+em { font-style: italic; }
+strong { font-weight: bold; }
+
+ul { list-style-type: disc }
+
+dl.contents { margin-top: 0; }
+dt.contents { margin-bottom: 0; }
+
+p.verse {
+  white-space: pre;
+  margin-left: 5%;
+}
+
+pre {
+  white-space: pre;
+  font-family: monospace;
+  margin-left: 5%;
+}
+</style>"
+  "The style sheet used for each wiki page.
+This can either be an inline stylesheet, using <style></style> tags,
+or an external stylesheet reference using a <link> tag.
+
+Here is an example of using a <link> tag:
+
+  <link rel=\"stylesheet\" type=\"text/css\" href=\"emacs-wiki.css\">"
+  :type 'string
+  :group 'emacs-wiki-publish)
+
+(defvar emacs-wiki-publishing-p nil
+  "Set to t while Wiki pages are being published.
+This can be used by <lisp> tags to know when HTML is being generated.")
+
+(defcustom emacs-wiki-block-groups-regexp
+  "\\(h[1-9r]\\|[oud]l\\|table\\|center\\|blockquote\\|pre\\)[^>]*"
+  "This regexp identifies HTML tag which defines their own blocks.
+That is, they do not need to be surrounded by <p>."
+  :type 'regexp
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-table-attributes "border=\"2\" cellpadding=\"5\""
+  "The attribute to be used with HTML <table> tags.
+Note that since emacs-wiki support direct insertion of HTML tags, you
+can easily create any kind of table you want, as long as every line
+begins at column 0 (to prevent it from being blockquote'd).  To make
+really ANYTHING you want, use this idiom:
+
+  <verbatim>
+  <table>
+    [... contents of my table, in raw HTML ...]
+  </verbatim></table>
+
+It may look strange to have the tags out of sequence, but remember
+that verbatim is processed long before table is even seen."
+  :type 'string
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-report-threshhold 100000
+  "If a Wiki file is this size or larger, report publishing progress."
+  :type 'integer
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-publishing-markup
+  (list
+   ["&\\([-A-Za-z_#0-9]+\\);" 0 emacs-wiki-markup-entity]
+
+   ;; change the displayed title or the stylesheet for a given page
+   ["\\`#\\(title\\|style\\)\\s-+\\(.+\\)\n+" 0
+    emacs-wiki-markup-initial-directives]
+
+   ;; process any markup tags
+   [emacs-wiki-tag-regexp 0 emacs-wiki-markup-custom-tags]
+
+   ;; emphasized or literal text
+   ["\\(^\\|[-[ \t\n<('`\"]\\)\\(=[^= \t\n]\\|_[^_ \t\n]\\|\\*+[^* \t\n]\\)"
+    2 emacs-wiki-markup-word]
+
+   ;; headings, outline-mode style
+   ["^\\(\\*+\\)\\s-+" 0 emacs-wiki-markup-heading]
+
+   ;; define anchor points
+   ["^#\\([A-Za-z0-9_%]+\\)\\s-*" 0 emacs-wiki-markup-anchor]
+
+   ;; horizontal rule, or section separator
+   ["^----+" 0 "<hr>"]
+
+   ;; footnotes section is separated by a horizontal rule in HTML
+   ["^\\(\\* \\)?Footnotes:?\\s-*" 0 "<hr>\n<p>\n"]
+   ;; footnote definition/reference (def if at beginning of line)
+   ["\\[\\([1-9][0-9]*\\)\\]" 0 emacs-wiki-markup-footnote]
+
+   ;; don't require newlines between numbered and unnumbered lists.
+   ;; This must come before paragraphs are calculated, so that any
+   ;; extra newlines added will be condensed.
+   ["^\\s-*\\(-\\|[0-9]+\\.\\)" 1 "\n\\1"]
+
+   ;; the beginning of the buffer begins the first paragraph
+   ["\\`\n*" 0 "<p>\n"]
+   ;; plain paragraph separator
+   ["\n\\([ \t]*\n\\)+" 0 "\n\n</p>\n\n<p>\n"]
+
+   ;; if table.el was loaded, allow for pretty tables.  otherwise only
+   ;; simple table markup is supported, nothing fancy.  use | to
+   ;; separate cells, || to separate header elements, and ||| for
+   ;; footer elements
+   (vector
+    (if (featurep 'table)
+       "^\\(\\s-*\\)\\(\\+[-+]+\\+[\n\r \t]+|\\)"
+      "^\\s-*\\(\\([^|\n]+\\(|+\\)\\s-*\\)+\\)\\([^|\n]+\\)?$")
+    1 'emacs-wiki-markup-table)
+
+   ;; unnumbered List items begin with a -.  numbered list items
+   ;; begin with number and a period.  definition lists have a
+   ;; leading term separated from the body with ::.  centered
+   ;; paragraphs begin with at least six columns of whitespace; any
+   ;; other whitespace at the beginning indicates a blockquote.  The
+   ;; reason all of these rules are handled here, is so that
+   ;; blockquote detection doesn't interfere with indented list
+   ;; members.
+   ["^\\(\\s-*\\(-\\|[0-9]+\\.\\|\\(.+\\)[ \t]+::\n?\\)\\)?\\([ \t]+\\)" 4
+    emacs-wiki-markup-list-or-paragraph]
+
+   ;; "verse" text is indicated the same way as a quoted e-mail
+   ;; response: "> text", where text may contain initial whitespace
+   ;; (see below).
+   ["<p>\\s-+> \\(\\([^\n]\n?\\)+\\)\\(\\s-*</p>\\)?" 0
+    emacs-wiki-markup-verse]
+
+   ;; join together the parts of a list
+   ["</\\([oud]l\\)>\\s-*\\(</p>\\s-*<p>\\s-*\\)?<\\1>\\s-*" 0 ""]
+
+   ;; join together the parts of a table
+   (vector
+    (concat "</tbody>\\s-*"
+           "</table>\\s-*" "\\(</p>\\s-*<p>\\s-*\\)?" "<table[^>]*>\\s-*"
+           "<tbody>\\s-*") 0 "")
+   ["</table>\\s-*\\(</p>\\s-*<p>\\s-*\\)?<table[^>]*>\\s-*" 0 ""]
+
+   ;; fixup paragraph delimiters
+   (vector
+    (concat "<p>\\s-*\\(</?" emacs-wiki-block-groups-regexp ">\\)") 0 "\\1")
+   (vector (concat "\\(</?" emacs-wiki-block-groups-regexp
+                  ">\\)\\s-*\\(</p>\\)") 3 "\\1")
+
+   ;; terminate open paragraph at the end of the buffer
+   ["<p>\\s-*\\'" 0 ""]
+   ;; make sure to close any open text (paragraphs)
+   ["\\([^> \t\n]\\)\\s-*\\'" 0 "\\1\n</p>"]
+   ;; lists have no whitespace after them, so add a final linebreak
+   ["\\(</[oud]l>\\)\\(\\s-*\\(<hr>\\|\\'\\)\\)" 0 "\\1\n<br>\\2"]
+
+   ;; replace WikiLinks in the buffer (links to other pages)
+   ;; <nop> before a WikiName guards it from being replaced
+   ;; '''' can be used to add suffixes, such as WikiName''''s
+   [emacs-wiki-url-or-name-regexp 0 emacs-wiki-markup-link]
+   ["''''" 0 ""]
+
+   ;; bare email addresses
+   (vector
+    (concat
+     "\\([^:.@/a-zA-Z0-9]\\)"
+     "\\([-a-zA-Z0-9._]+@\\([-a-zA-z0-9_]+\\.\\)+[a-zA-Z0-9]+\\)"
+     "\\([^\"a-zA-Z0-9]\\)")
+    0
+    "\\1<a href=\"mailto:\\2\">\\2</a>\\4")
+
+   ;; replace quotes, since most browsers don't understand `` and ''
+   ["\\(``\\|''\\)" 0 "\""]
+
+   ;; insert the default publishing header
+   (function
+    (lambda ()
+      (insert emacs-wiki-publishing-header)))
+
+   ;; insert the default publishing footer
+   (function
+    (lambda ()
+      (goto-char (point-max))
+      (insert emacs-wiki-publishing-footer)))
+
+   ;; process any remaining markup tags
+   [emacs-wiki-tag-regexp 0 emacs-wiki-markup-custom-tags])
+  "List of markup rules to apply when publishing a Wiki page.
+Each member of the list is either a function, or a vector of the form:
+
+  [REGEXP/SYMBOL TEXT-BEGIN-GROUP REPLACEMENT-TEXT/FUNCTION/SYMBOL].
+
+REGEXP is a regular expression, or symbol whose value is a regular
+expression, which is searched for using `re-search-forward'.
+TEXT-BEGIN-GROUP is the matching group within that regexp which
+denotes the beginning of the actual text to be marked up.
+REPLACEMENT-TEXT is a string that will be passed to `replace-match'.
+If it is not a string, but a function, it will be called to determine
+what the replacement text should be (it must return a string).  If it
+is a symbol, the value of that symbol should be a string.
+
+The replacements are done in order, one rule at a time.  Writing the
+regular expressions can be a tricky business.  Note that case is never
+ignored.  `case-fold-search' is always be bound to nil while
+processing the markup rules.
+
+Here is a description of the default markup rules:
+
+Headings
+
+ * First level
+ ** Second level
+ *** Third level
+
+ Note that the first level is actually indicated using H2, so that
+ it doesn't appear at the same level as the page heading (which
+ conceptually titles the section of that Wiki page).
+
+Horizontal rules
+
+----
+
+Emphasis
+
+ *emphasis*
+ **strong emphasis**
+ ***very strong emphasis***
+ _underlined text_
+ =verbatim=
+
+ <verbatim>This tag should be used for larger blocks of
+ text</verbatim>.
+
+Footnotes
+
+  A reference[1], which is just a number in square brackets,
+  constitutes a footnote reference.
+
+  Footnotes:
+
+  [1]  Footnotes are defined by the same number in brackets
+       occurring at the beginning of a line.  Use footnote-mode's C-c
+       ! a command, to very easily insert footnotes while typing.  Use
+       C-x C-x to return to the point of insertion.
+
+Paragraphs
+
+  One or more blank lines separates paragraphs.
+
+Centered paragraphs and quotations
+
+  A line that begins with six or more columns of whitespace (made up
+  of tabs or spaces) indicates a centered paragraph.  I assume this
+  because it's expected you will use M-s to center the line, which
+  usually adds a lot of whitespace before it.
+
+  If a line begins with some whitespace, but less than six columns, it
+  indicates a quoted paragraph.
+
+Poetic verse
+
+  Poetry requires that whitespace be preserved, without resorting to
+  the monospace typical of <pre>.  For this, the following special
+  markup exists, which is reminiscent of e-mail quotations:
+
+    > A line of Emacs verse;
+    > forgive its being so terse.
+
+  You can also use the <verse> tag, if you prefer:
+
+    <verse>
+    A line of Emacs verse;
+    forgive its being so terse.
+    </verse>
+
+Literal paragraphs
+
+  Use the HTML tags <pre></pre> to insert a paragraph and preserve
+  whitespace.  If you're inserting a block of code, you will almost
+  always want to use <verbatim></verbatim> *within* the <pre> tags.
+  The shorcut for doing this is to use the <example> tag:
+
+    <example>
+    Some literal text or code here.
+    </example>
+
+Lists
+
+  - bullet list
+
+  1. Enumerated list
+
+  Term :: A definition list
+
+  Blank lines between list elements are optional, but required between
+  members of a definition list.
+
+Tables
+
+  There are two forms of table markup supported.  If Takaaki Ota's
+  table.el package is available, then simply create your tables using
+  his package, and they will be rendered into the appropriate HTML.
+
+  If table.el is not available, then only very simple table markup is
+  supported.  The attributes of the table are kept in
+  `emacs-wiki-table-attributes'.  The syntax is:
+
+    Double bars || Separate header fields
+    Single bars | Separate body fields
+    Here are more | body fields
+    Triple bars ||| Separate footer fields
+
+  Other paragraph markup applies to both styles, meaning that if six
+  or more columns of whitespace precedes the first line of the table,
+  it will be centered, and if any whitespace at all precedes first
+  line, it will occur in a blockquote.
+
+Anchors and tagged links
+
+  #example If you begin a line with \"#anchor\" -- where anchor
+  can be any word that doesn't contain whitespace -- it defines an
+  anchor at that point into the document.  This anchor text is not
+  displayed.
+
+  You can reference an anchored point in another page (or even in the
+  current page) using WikiName#anchor.  The #anchor will never be
+  displayed in HTML, whether at the point of definition or reference,
+  but it will cause browsers to jump to that point in the document.
+
+Redirecting to another page or URL
+
+  Sometimes you may wish to redirect someone to another page.  To do
+  this, put:
+
+    <redirect url=\"http://somewhereelse.com\"/>
+
+  at the top of the page.  If the <redirect> tag specifies content,
+  this will be used as the redirection message, rather than the
+  default.
+
+  The numbers of seconds to delay is defined by
+  `emacs-wiki-redirect-delay', which defaults to 2 seconds.  The page
+  shown will also contain a link to click on, for browsing which do
+  not support automatic refreshing.
+
+URLs
+
+  A regular URL is given as a link.  If it's an image URL, it will
+  be inlined using an IMG tag.
+
+Embedded lisp
+
+  <lisp>(concat \"This form gets\" \"inserted\")</lisp>
+
+Special handling of WikiNames
+
+  If you need to add a plural at the end of a WikiName, separate it
+  with four single quotes: WikiName''''s.
+
+  To prevent a link name (of any type) from being treated as such,
+  surround it with =equals= (to display it in monotype), or prefix it
+  with the tag <nop>.
+
+Special Wiki links
+
+  Besides the normal WikiName type links, emacs-wiki also supports
+  extended links:
+
+    [[link text][optional link description]]
+
+  An extended link is always a link, no matter how it looks.  This
+  means you can use any file in your `emacs-wiki-directories' as a
+  Wiki file.  If you provide an optional description, that's what will
+  be shown instead of the link text.  This is very useful for
+  providing textual description of URLs.
+
+  See the documentation to emacs-wiki-image-regexp for how to inline
+  files and images.
+
+InterWiki names
+
+  There are times when you will want to constantly reference pages on
+  another website.  Rather than repeating the URL ad nauseum, you can
+  define an InterWiki name.  This is a set of WikiNames to URL
+  correlations, that support textual substitution using #anchor names
+  (which are appended to the URL).  For example, MeatballWiki is
+  defined in the variable `emacs-wiki-interwiki-names'.  It means you
+  can reference the page \"MeatBall\" on MeatballWiki using this
+  syntax:
+
+    MeatballWiki#MeatBall
+
+  In the resulting HTML, the link is simply shown as
+  \"MeatballWiki:MeatBall\"."
+  :type '(repeat
+         (choice
+          (vector :tag "Markup rule"
+                  (choice regexp symbol)
+                  integer
+                  (choice string function symbol))
+          function))
+  :group 'emacs-wiki-publish)
+
+(defcustom emacs-wiki-changelog-markup
+  (list
+   ;; process any custom markup tags
+   [emacs-wiki-tag-regexp 0 emacs-wiki-markup-custom-tags]
+
+   ["&" 0 "&amp;"]
+   ["<" 0 "&lt;"]
+   [">" 0 "&gt;"]
+
+   ["^\\(\\S-+\\)\\s-+\\(.+\\)" 0 emacs-wiki-markup-changelog-section]
+
+   ;; emphasized or literal text
+   ["\\(^\\|[-[ \t\n<('`\"]\\)\\(=[^= \t\n]\\|_[^_ \t\n]\\|\\*+[^* \t\n]\\)"
+    2 emacs-wiki-markup-word]
+
+   ;; headings, outline-mode style
+   ["^\\*\\s-+\\(.+\\)$" 0 "<h2>\\1</h2>"]
+
+   ;; escape the 'file' entries, incase they are extended wiki links
+   ["^[ \t]+\\* \\([^:(]+\\)\\([ \t]+(\\|:\\)" 0 emacs-wiki-changelog-escape-files]
+
+   ;; don't require newlines between unnumbered lists.
+   ["^\\s-*\\(\\*\\)" 1 "\n\\1"]
+
+   ;; the beginning of the buffer begins the first paragraph
+   ["\\`\n*" 0 "<p>\n"]
+   ;; plain paragraph separator
+   ["\n\\([ \t]*\n\\)+" 0 "\n\n</p>\n\n<p>\n"]
+
+   ;; unnumbered List items begin with a -.  numbered list items
+   ;; begin with number and a period.  definition lists have a
+   ;; leading term separated from the body with ::.  centered
+   ;; paragraphs begin with at least six columns of whitespace; any
+   ;; other whitespace at the beginning indicates a blockquote.  The
+   ;; reason all of these rules are handled here, is so that
+   ;; blockquote detection doesn't interfere with indented list
+   ;; members.
+   ["^\\(\\s-*\\(\\*\\)\\)?\\([ \t]+\\)\\(\\([^\n]\n?\\)+\\)" 3
+    "<ul>\n<li>\\4</ul>\n"]
+
+   ;; join together the parts of a list
+   ["</\\([oud]l\\)>\\s-*\\(</p>\\s-*<p>\\s-*\\)?<\\1>\\s-*" 0 ""]
+
+   ;; fixup paragraph delimiters
+   (vector
+    (concat "<p>\\s-*\\(</?" emacs-wiki-block-groups-regexp ">\\)") 0 "\\1")
+   (vector (concat "\\(</?" emacs-wiki-block-groups-regexp
+                  ">\\)\\s-*\\(</p>\\)") 3 "\\1")
+
+   ;; terminate open paragraph at the end of the buffer
+   ["<p>\\s-*\\'" 0 ""]
+   ;; make sure to close any open text (paragraphs)
+   ["\\([^> \t\n]\\)\\s-*\\'" 0 "\\1\n</p>"]
+   ;; lists have no whitespace after them, so add a final linebreak
+   ["\\(</[oud]l>\\)\\(\\s-*\\(<hr>\\|\\'\\)\\)" 0 "\\1\n<br>\\2"]
+
+   ;; bare email addresses
+   (vector
+    (concat
+     "\\([^:.@/a-zA-Z0-9]\\)"
+     "\\([-a-zA-Z0-9._]+@\\([-a-zA-z0-9_]+\\.\\)+[a-zA-Z0-9]+\\)"
+     "\\([^\"a-zA-Z0-9]\\)")
+    0
+    "\\1<a href=\"mailto:\\2\">\\2</a>\\4")
+
+   ;; replace WikiLinks in the buffer (links to other pages)
+   [emacs-wiki-url-or-name-regexp 0 emacs-wiki-markup-link]
+   ["''''" 0 ""]
+
+   ;; insert the default publishing header
+   (function
+    (lambda ()
+      (insert emacs-wiki-publishing-header)))
+
+   ;; insert the default publishing footer
+   (function
+    (lambda ()
+      (goto-char (point-max))
+      (insert emacs-wiki-publishing-footer))))
+  "List of markup rules for publishing ChangeLog files.
+These are used when the wiki page's name is ChangeLog."
+  :type '(repeat
+         (choice
+          (vector :tag "Markup rule"
+                  (choice regexp symbol)
+                  integer
+                  (choice string function symbol))
+          function))
+  :group 'emacs-wiki-publish)
+
+(defun emacs-wiki-transform-content-type (content-type)
+  "Using `emacs-wiki-coding-map', try and resolve an emacs coding
+  system to an associated HTML coding system. If no match is found,
+  `emacs-wiki-charset-default' is used instead."
+  (let ((match (assoc (coding-system-base content-type)
+                      emacs-wiki-coding-map)))
+    (if match
+        (cadr match)
+      emacs-wiki-charset-default)))
+
+(defun emacs-wiki-private-p (name)
+  "Return non-nil if NAME is a private page, and shouldn't be published."
+  (if name
+      (if emacs-wiki-use-mode-flags
+         (let* ((page-file (emacs-wiki-page-file name t))
+                (filename (and page-file (file-truename page-file))))
+           (if filename
+               (or (eq ?- (aref (nth 8 (file-attributes
+                                        (file-name-directory filename))) 7))
+                   (eq ?- (aref (nth 8 (file-attributes filename)) 7)))))
+       (let ((private-pages emacs-wiki-private-pages) private)
+         (while private-pages
+           (if (string-match (car private-pages) name)
+               (setq private t private-pages nil)
+             (setq private-pages (cdr private-pages))))
+         private))))
+
+(defun emacs-wiki-editable-p (name)
+  "Return non-nil if NAME is a page that may be publically edited.
+If the page does not exist, the page will be created if: mode flags
+are not being checked, and it is a page listed in
+`emacs-wiki-editable-pages', or the first directory in
+`emacs-wiki-directories' is writable.  In either case, the new page
+will be created in the first directory in `emacs-wiki-directories'."
+  (if (and name emacs-wiki-http-support-editing)
+      (if emacs-wiki-use-mode-flags
+         (let ((filename
+                (file-truename
+                 (or (emacs-wiki-page-file name t)
+                     (expand-file-name name (car emacs-wiki-directories))))))
+           (if (file-exists-p filename)
+               (eq ?w (aref (nth 8 (file-attributes filename)) 8))
+             (eq ?w (aref (nth 8 (file-attributes
+                                  (file-name-directory filename))) 8))))
+       (let ((editable-pages emacs-wiki-editable-pages) editable)
+         (while editable-pages
+           (if (string-match (car editable-pages) name)
+               (setq editable t editable-pages nil)
+             (setq editable-pages (cdr editable-pages))))
+         editable))))
+
+(defun emacs-wiki-visit-published-file (&optional arg)
+  "Visit the current wiki page's published result."
+  (interactive "P")
+  (if arg
+      (find-file-other-window (emacs-wiki-published-file))
+    (funcall emacs-wiki-browse-url-function
+            (concat "file:" (emacs-wiki-published-file)))))
+
+(defun emacs-wiki-dired-publish ()
+  "Publish all marked files in a dired buffer."
+  (interactive)
+  (emacs-wiki-publish-files (dired-get-marked-files) t))
+
+(defun emacs-wiki-prettify-title (title)
+  "Prettify the given TITLE."
+  (save-match-data
+    (let ((case-fold-search nil))
+      (while (string-match "\\([A-Za-z]\\)\\([A-Z0-9]\\)" title)
+       (setq title (replace-match "\\1 \\2" t nil title)))
+      (let* ((words (split-string title))
+            (w (cdr words)))
+       (while w
+         (if (member (downcase (car w))
+                     emacs-wiki-downcase-title-words)
+             (setcar w (downcase (car w))))
+         (setq w (cdr w)))
+       (mapconcat 'identity words " ")))))
+
+(defun emacs-wiki-publish (&optional arg)
+  "Publish all wikis that need publishing.
+If the published wiki already exists, it is only overwritten if the
+wiki is newer than the published copy.  When given the optional
+argument ARG, all wikis are rewritten, no matter how recent they are.
+The index file is rewritten no matter what."
+  (interactive "P")
+  ;; prompt to save any emacs-wiki buffers
+  (save-some-buffers nil (lambda ()
+                           (eq major-mode 'emacs-wiki-mode)))
+  ;; ensure the publishing location is available
+  (unless (file-exists-p emacs-wiki-publishing-directory)
+    (message "Creating publishing directory %s"
+             emacs-wiki-publishing-directory)
+    (make-directory emacs-wiki-publishing-directory))
+  (if (emacs-wiki-publish-files
+       (let* ((names (emacs-wiki-file-alist))
+             (files (list t))
+             (lfiles files))
+        (while names
+          (setcdr lfiles (cons (cdar names) nil))
+          (setq lfiles (cdr lfiles)
+                names (cdr names)))
+        (cdr files)) arg)
+      ;; republish the index if any pages were published
+      (with-current-buffer (emacs-wiki-generate-index t t)
+       (emacs-wiki-replace-markup emacs-wiki-index-page)
+       (let ((backup-inhibited t))
+         (write-file (emacs-wiki-published-file emacs-wiki-index-page)))
+       (kill-buffer (current-buffer))
+       (message "All Wiki pages%s have been published."
+                (if emacs-wiki-current-project
+                    (concat " for project " emacs-wiki-current-project)
+                  "")))
+    (message "No Wiki pages%s need publishing at this time."
+            (if emacs-wiki-current-project
+                (concat " in project " emacs-wiki-current-project)
+              ""))))
+
+(defun emacs-wiki-publish-this-page ()
+  "Force publication of the current page."
+  (interactive)
+  (emacs-wiki-publish-files (list buffer-file-name) t))
+
+(defun emacs-wiki-publish-files (files force)
+  "Publish all files in list FILES.
+If the argument FORCE is nil, each file is only published if it is
+newer than the published version.  If the argument FORCE is non-nil,
+the file is published no matter what."
+  (let (published-some file page published)
+    (while files
+      (setq file (car files)
+           files (cdr files)
+           page (emacs-wiki-page-name file)
+            published (emacs-wiki-published-file page))
+      (if (and (not (emacs-wiki-private-p page))
+              (or force (file-newer-than-file-p file published)))
+         (with-temp-buffer
+           (insert-file-contents file t)
+            (cd (file-name-directory file))
+           (emacs-wiki-maybe)
+           (emacs-wiki-replace-markup)
+            (let ((backup-inhibited t)
+                  (buffer-file-coding-system
+                   (when (boundp 'buffer-file-coding-system)
+                     buffer-file-coding-system)))
+              (when (eq buffer-file-coding-system 'undecided-unix)
+                ;; make it agree with the default charset
+                (setq buffer-file-coding-system
+                      emacs-wiki-coding-default))
+              (write-file published))
+            (setq published-some t))))
+    published-some))
+
+
+
+(defun emacs-wiki-escape-html-specials (&optional end)
+  (while (and (or (< (point) end) (not end))
+              (re-search-forward "[<>&\"]" end t))
+    (cond
+     ((eq (char-before) ?\")
+      (delete-char -1)
+      (insert "&quot;"))
+     ((eq (char-before) ?\<)
+      (delete-char -1)
+      (insert "&lt;"))
+     ((eq (char-before) ?\>)
+      (delete-char -1)
+      (insert "&gt;"))
+     ((eq (char-before) ?\&)
+      (delete-char -1)
+      (insert "&amp;")))))
+
+;; we currently only do this on links. this means a stray '&' in an
+;; emacs-wiki document risks being misinterpreted when being published, but
+;; this is the price we pay to be able to inline HTML content without special
+;; tags.
+(defun emacs-wiki-escape-html-string (str)
+  "Convert to character entities any non alphanumeric characters outside of a
+  few punctuation symbols, that risk being misinterpreted if not escaped"
+  (when str
+    (let (pos code len)
+      (save-match-data
+        (while (setq pos (string-match "[^-[:alnum:]/:._=@\\?~#]" str pos))
+          (setq code (int-to-string (aref str pos))
+               len (length code)
+               str (replace-match (concat "&#" code ";") nil nil str)
+               pos (+ 3 len pos)))
+        str))))
+
+(defun emacs-wiki-replace-markup (&optional title)
+  "Replace markup according to `emacs-wiki-publishing-markup'."
+  (let* ((emacs-wiki-meta-http-equiv emacs-wiki-meta-http-equiv)
+        (emacs-wiki-current-page-title title)
+        (emacs-wiki-publishing-p t)
+        (case-fold-search nil)
+        (inhibit-read-only t)
+        (rules (if (string= (emacs-wiki-page-name) "ChangeLog")
+                   emacs-wiki-changelog-markup
+                 emacs-wiki-publishing-markup))
+        (limit (* (length rules) (point-max)))
+        (verbose (and emacs-wiki-report-threshhold
+                      (> (point-max) emacs-wiki-report-threshhold)))
+        (base 0)
+         (emacs-wiki-meta-content
+         (concat emacs-wiki-meta-content-type "; charset="
+                  (if (stringp emacs-wiki-meta-content-coding)
+                      emacs-wiki-meta-content-coding
+                    (emacs-wiki-transform-content-type
+                     (or buffer-file-coding-system
+                         emacs-wiki-coding-default))))))
+    (run-hooks 'emacs-wiki-before-markup-hook)
+    (while rules
+      (goto-char (point-min))
+      (if (functionp (car rules))
+         (funcall (car rules))
+       (let ((regexp (aref (car rules) 0))
+             (group (aref (car rules) 1))
+             (replacement (aref (car rules) 2))
+             start last-pos pos)
+         (if (symbolp regexp)
+             (setq regexp (symbol-value regexp)))
+         (if verbose
+             (message "Publishing %s...%d%%"
+                      (emacs-wiki-page-name)
+                      (* (/ (float (+ (point) base)) limit) 100)))
+         (while (and regexp (setq pos (re-search-forward regexp nil t)))
+           (if verbose
+               (message "Publishing %s...%d%%"
+                        (emacs-wiki-page-name)
+                        (* (/ (float (+ (point) base)) limit) 100)))
+           (unless (get-text-property (match-beginning group) 'read-only)
+             (let ((text (cond
+                          ((functionp replacement)
+                           (funcall replacement))
+                          ((symbolp replacement)
+                           (symbol-value replacement))
+                          (t replacement))))
+               (when text
+                  (condition-case nil
+                      (replace-match text t)
+                    (error
+                     (replace-match "[FIXME: invalid characters]" t))))))
+                (if (and last-pos (= pos last-pos))
+                    (if (eobp)
+                        (setq regexp nil)
+                      (forward-char 1)))
+                (setq last-pos pos))))
+          (setq rules (cdr rules)
+                base (+ base (point-max))))
+        (run-hooks 'emacs-wiki-after-markup-hook)
+        (if verbose
+            (message "Publishing %s...done" (emacs-wiki-page-name)))))
+
+(defun emacs-wiki-custom-tags (&optional highlight-p)
+  (let ((tag-info (or (assoc (match-string 1) emacs-wiki-markup-tags)
+                     (assoc (match-string 1) emacs-wiki-dangerous-tags))))
+    (when (and tag-info (or (not highlight-p)
+                           (nth 3 tag-info)))
+      (let ((closed-tag (match-string 3))
+           (start (match-beginning 0))
+           (beg (point)) end attrs)
+       (when (nth 2 tag-info)
+         (let ((attrstr (match-string 2)))
+           (while (and attrstr
+                       (string-match
+                        "\\([^ \t\n=]+\\)\\(=\"\\([^\"]+\\)\"\\)?" attrstr))
+             (let ((attr (cons (downcase
+                                (match-string-no-properties 1 attrstr))
+                               (match-string-no-properties 3 attrstr))))
+               (setq attrstr (replace-match "" t t attrstr))
+               (if attrs
+                   (nconc attrs (list attr))
+                 (setq attrs (list attr)))))))
+       (if (and (cadr tag-info) (not closed-tag))
+           (if (search-forward (concat "</" (car tag-info) ">") nil t)
+               (unless highlight-p
+                 (delete-region (match-beginning 0) (point)))
+             (setq tag-info nil)))
+       (when tag-info
+         (setq end (point-marker))
+         (unless highlight-p
+           (delete-region start beg))
+         (goto-char (if highlight-p beg start))
+         (let ((args (list start end)))
+           (if (nth 2 tag-info)
+               (nconc args (list attrs)))
+           (if (nth 3 tag-info)
+               (nconc args (list highlight-p)))
+           (apply (nth 4 tag-info) args))))))
+  nil)
+
+(defun emacs-wiki-markup-initial-directives ()
+  (cond
+   ((string= (match-string 1) "title")
+    (set (make-local-variable 'emacs-wiki-current-page-title) (match-string 2)))
+   (t ;; "style"
+    (set (make-local-variable 'emacs-wiki-style-sheet)
+         (concat "<link rel=\"stylesheet\" type=\"text/css\" href=\""
+                 (match-string 2) "\">"))))
+  "")
+
+(defalias 'emacs-wiki-markup-custom-tags 'emacs-wiki-custom-tags)
+
+(defun emacs-wiki-highlight-title ()
+  (add-text-properties (+ 7 (match-beginning 0))
+                       (line-end-position)
+                       '(face emacs-wiki-header-1)))
+
+(defun emacs-wiki-highlight-custom-tags ()
+  ;; Remove the match-data related to the url-or-name-regexp, which is
+  ;; part of emacs-wiki-highlight-regexp.  All in the name of speed.
+  (let ((match-data (match-data)))
+    (setcdr (cdr match-data)
+           (nthcdr (* 2 (+ 2 emacs-wiki-url-or-name-regexp-group-count))
+                   match-data))
+    (set-match-data match-data)
+    (emacs-wiki-custom-tags t)))
+
+(defun emacs-wiki-example-tag (beg end highlight-p)
+  (if highlight-p
+      (progn
+        (emacs-wiki-multiline-maybe beg end)
+        (goto-char end))
+    (insert "<pre class=\"example\">")
+    (emacs-wiki-escape-html-specials end)
+    (when (< (point) end)
+      (goto-char end))
+    (insert "</pre>")
+    (add-text-properties beg (point) '(rear-nonsticky (read-only)
+                                                      read-only t))))
+
+(defun emacs-wiki-verbatim-tag (beg end highlight-p)
+  (if highlight-p
+      (progn
+        (emacs-wiki-multiline-maybe beg end)
+        (goto-char end))
+    (emacs-wiki-escape-html-specials end)
+    (add-text-properties beg end '(rear-nonsticky (read-only)
+                                                 read-only t))))
+
+(defun emacs-wiki-nowiki-tag (beg end highlight-p)
+  (if highlight-p
+      (goto-char end)
+    (add-text-properties
+     beg end '(read-nonsticky (read-only) read-only t))))
+
+(defun emacs-wiki-verse-tag (beg end)
+  (save-excursion
+    (while (< (point) end)
+      (unless (eq (char-after) ?\n)
+       (insert "> "))
+      (forward-line))))
+
+(defvar emacs-wiki-numbered-counter 1)
+(make-variable-buffer-local 'emacs-wiki-numbered-counter)
+
+(defun emacs-wiki-numbered-tag (beg end)
+  (save-excursion
+    (goto-char beg)
+    (setq end (copy-marker (1- end)))
+    (insert "<table cellspacing=\"8\">")
+    (insert (format "<tr><td valign=\"top\"><strong>%d</strong></td>
+<td><p><a name=\"%d\"/>" emacs-wiki-numbered-counter
+                        emacs-wiki-numbered-counter))
+    (setq emacs-wiki-numbered-counter
+         (1+ emacs-wiki-numbered-counter))
+    (while (and (< (point) end)
+               (re-search-forward "^$" end t))
+      (replace-match (format "</p>
+</td>
+</tr><tr><td valign=\"top\"><strong>%d</strong></td><td>
+<p><a name=\"%d\"/>" emacs-wiki-numbered-counter
+                    emacs-wiki-numbered-counter))
+      (setq emacs-wiki-numbered-counter
+           (1+ emacs-wiki-numbered-counter)))
+    (goto-char end)
+    (insert (format "</p>
+</td></tr></table>" (1+ emacs-wiki-numbered-counter)))))
+
+(defun emacs-wiki-redirect-tag (beg end attrs)
+  (let ((link (cdr (assoc "url" attrs))))
+    (when link
+      (setq emacs-wiki-meta-http-equiv "Refresh"
+           emacs-wiki-meta-content
+           (concat (or (cdr (assoc "delay" attrs))
+                       (int-to-string emacs-wiki-redirect-delay))
+                   ";\nURL=" (emacs-wiki-link-url link)))
+      (if (= beg end)
+         (insert "You should momentarily be redirected to [[" link "]].")
+       (goto-char end))
+      (delete-region (point) (point-max)))))
+
+(defun emacs-wiki-nop-tag (beg end highlight-p)
+  (if highlight-p
+      (add-text-properties beg (point) '(invisible t intangible t)))
+  (when (looking-at emacs-wiki-name-regexp)
+    (goto-char (match-end 0))
+    (unless highlight-p
+      (add-text-properties beg (point)
+                          '(rear-nonsticky (read-only) read-only t)))))
+
+(defun emacs-wiki-insert-anchor (anchor)
+  "Insert an anchor, either around the word at point, or within a tag."
+  (skip-chars-forward " \t\n")
+  (if (looking-at "<\\([^ />]+\\)>")
+      (let ((tag (match-string 1)))
+       (goto-char (match-end 0))
+       (insert "<a name=\"" anchor "\" id=\"" anchor "\">")
+        (when emacs-wiki-anchor-on-word
+          (or (and (search-forward (format "</%s>" tag)
+                                   (line-end-position) t)
+                   (goto-char (match-beginning 0)))
+              (forward-word 1)))
+       (insert "</a>"))
+    (insert "<a name=\"" anchor "\" id=\"" anchor "\">")
+    (when emacs-wiki-anchor-on-word
+      (forward-word 1))
+    (insert "</a>")))
+
+(defun emacs-wiki-contents-tag (beg end attrs)
+  (let ((max-depth (let ((depth (cdr (assoc "depth" attrs))))
+                    (or (and depth (string-to-int depth)) 2)))
+       (index 1)
+       base contents l)
+    (save-excursion
+      (catch 'done
+       (while (re-search-forward "^\\(\\*+\\)\\s-+\\(.+\\)" nil t)
+         (setq l (length (match-string 1)))
+         (if (null base)
+             (setq base l)
+           (if (< l base)
+               (throw 'done t)))
+         (when (<= l max-depth)
+           (setq contents (cons (cons l (match-string-no-properties 2))
+                                contents))
+           (goto-char (match-beginning 2))
+           (emacs-wiki-insert-anchor (concat "sec" (int-to-string index)))
+           (setq index (1+ index))))))
+    (setq index 1 contents (reverse contents))
+    (let ((depth 1) (sub-open 0) (p (point)))
+      (insert "<dl class=\"contents\">\n")
+      (while contents
+       (insert "<dt class=\"contents\">\n")
+       (insert "<a href=\"#sec" (int-to-string index) "\">"
+                (cdar contents)
+                "</a>\n")
+       (setq index (1+ index))
+       (insert "</dt>\n")
+       (setq depth (caar contents)
+             contents (cdr contents))
+       (if contents
+           (cond
+            ((< (caar contents) depth)
+             (let ((idx (caar contents)))
+               (while (< idx depth)
+                 (insert "</dl>\n</dd>\n")
+                 (setq sub-open (1- sub-open)
+                       idx (1+ idx)))))
+            ((> (caar contents) depth) ; can't jump more than one ahead
+             (insert "<dd>\n<dl class=\"contents\">\n")
+             (setq sub-open (1+ sub-open))))))
+      (while (> sub-open 0)
+       (insert "</dl>\n</dd>\n")
+       (setq sub-open (1- sub-open)))
+      (insert "</dl>\n")
+      (put-text-property p (point) 'read-only t))))
+
+(defun emacs-wiki-lisp-tag (beg end highlight-p)
+  (if highlight-p
+      (add-text-properties
+       beg end
+       (list 'font-lock-multiline t
+            'display (emacs-wiki-eval-lisp
+                      (buffer-substring-no-properties (+ beg 6) (- end 7)))
+            'intangible t))
+    (save-excursion
+      (insert (emacs-wiki-eval-lisp
+              (prog1
+                  (buffer-substring-no-properties beg end)
+                (delete-region beg end)))))))
+
+(defcustom emacs-wiki-command-default-file nil
+  "If non-nil, this default program to use with <command> tags.
+If nil, Eshell is used, since it works on all platforms."
+  :type '(choice file (const :tag "Use Eshell" nil))
+  :group 'emacs-wiki-publish)
+
+(defun emacs-wiki-command-tag (beg end attrs &optional highlight-p pre-tags)
+  (if highlight-p
+      (goto-char end)
+    (while (looking-at "\\s-*$")
+      (forward-line))
+    (let ((interp (or (cdr (assoc "file" attrs))
+                     emacs-wiki-command-default-file)))
+      (if (null interp)
+         (eshell-command (prog1
+                             (buffer-substring-no-properties (point) end)
+                           (delete-region beg end)) t)
+       (let ((file (make-temp-file "ewiki")))
+         (unwind-protect
+             (let ((args (split-string interp)))
+               (write-region (point) end file)
+               (delete-region beg end)
+               (if pre-tags
+                   (insert "<pre>\n"))
+               (apply 'call-process (car args) file t nil (cdr args))
+               (while (eq (char-syntax (char-before)) ? )
+                 (backward-char))
+               (add-text-properties beg (point)
+                                    '(rear-nonsticky (read-only)
+                                                     read-only t))
+               (if pre-tags
+                   (insert "</pre>\n")))
+           (if (file-exists-p file)
+               (delete-file file))))))))
+
+(defcustom emacs-wiki-c-to-html
+  (if (or (featurep 'executable)
+         (load "executable" t t))
+      (concat (executable-find "c2html") " -c -s"))
+  "Program to use to convert <c-source> tag text to HTML."
+  :type 'string
+  :group 'emacs-wiki-publish)
+
+(defun emacs-wiki-c-source-tag (beg end attrs highlight-p)
+  (if highlight-p
+      (goto-char end)
+    (if emacs-wiki-c-to-html
+       (let ((c-to-html emacs-wiki-c-to-html))
+         (if (assoc "numbered" attrs)
+             (setq c-to-html (concat c-to-html " -n")))
+         (emacs-wiki-command-tag beg end (list (cons "file" c-to-html))))
+      (insert "<pre>")
+      (emacs-wiki-escape-html-specials end)
+      (goto-char end)
+      (add-text-properties beg (point)
+                          '(rear-nonsticky (read-only) read-only t))
+      (insert "</pre>"))))
+
+(defun emacs-wiki-python-tag (beg end attrs highlight-p)
+  (emacs-wiki-command-tag
+   beg end (list (cons "file" (executable-find "python"))) highlight-p t))
+
+(defun emacs-wiki-perl-tag (beg end attrs highlight-p)
+  (emacs-wiki-command-tag
+   beg end (list (cons "file" (executable-find "perl"))) highlight-p t))
+
+(defun emacs-wiki-insert-xbel-bookmarks (bmarks folder)
+  "Insert a set of XBEL bookmarks as an HTML list."
+  (while bmarks
+    (let ((bookmark (car bmarks)))
+      (cond
+       ((equal (xml-tag-name bookmark) "folder")
+       (let ((title (cadr (xml-tag-child bookmark "title"))))
+         (unless folder
+           (insert "<li>" title "\n<ul>\n"))
+         (emacs-wiki-insert-xbel-bookmarks (xml-tag-children bookmark)
+                                           (if (equal folder title)
+                                               nil
+                                             folder))
+         (unless folder
+           (insert "</ul>\n"))))
+       ((equal (xml-tag-name bookmark) "bookmark")
+       (unless folder
+         (insert "<li><a href=\"" (xml-tag-attr bookmark "href") "\">"
+                 (cadr (xml-tag-child bookmark "title")) "</a>\n")))))
+    (setq bmarks (cdr bmarks))))
+
+(defcustom emacs-wiki-xbel-bin-directory "/usr/bin"
+  "Directory where the xbel parsing utilities reside."
+  :type 'directory
+  :group 'emacs-wiki-publish)
+
+(defun emacs-wiki-bookmarks-tag (beg end attrs)
+  (require 'xml-parse)
+  (let ((filename (expand-file-name (cdr (assoc "file" attrs))))
+       (type (cdr (assoc "type" attrs)))
+       (folder (cdr (assoc "folder" attrs)))
+       (this-buffer (current-buffer))
+       buffer)
+    (when filename
+      (cond
+       (type
+       (setq buffer (get-buffer-create " *xbel_parse*"))
+       (with-current-buffer buffer
+         (erase-buffer)
+         (call-process
+          (format "%s/%s_parse"
+                  (directory-file-name emacs-wiki-xbel-bin-directory) type)
+          nil t nil filename)))
+       (t
+       (setq buffer (find-file-noselect filename))))
+      (insert "<ul>\n")
+      (emacs-wiki-insert-xbel-bookmarks
+       (with-current-buffer buffer
+        (goto-char (point-min))
+        (when (re-search-forward "<!DOCTYPE\\s-+xbel" nil t) ; XBEL format
+          (goto-char (match-beginning 0))
+          ;; the `cdr' is to skip the "title" child
+          (cdr (xml-tag-children (read-xml))))) folder)
+      (insert "</ul>\n")
+      (kill-buffer buffer)))
+  (while (eq (char-syntax (char-before)) ? )
+    (backward-char))
+  (add-text-properties beg (point)
+                      '(rear-nonsticky (read-only) read-only t)))
+
+(defun emacs-wiki-link-url (wiki-link)
+  "Resolve the given WIKI-LINK into its ultimate URL form."
+  (let ((link (emacs-wiki-wiki-link-target wiki-link)))
+    (save-match-data
+      (if (or (emacs-wiki-wiki-url-p link)
+             (string-match emacs-wiki-image-regexp link)
+             (string-match emacs-wiki-file-regexp link))
+         link
+       (if (assoc (emacs-wiki-wiki-base link)
+                  (emacs-wiki-file-alist t))
+           (if (string-match "#" link)
+               (concat (emacs-wiki-published-name
+                        (substring link 0 (match-beginning 0))
+                         (emacs-wiki-page-name)) "#"
+                       (substring link (match-end 0)))
+             (emacs-wiki-published-name link (emacs-wiki-page-name))))))))
+
+(defsubst emacs-wiki-link-href (url name)
+  "Return an href string for URL and NAME."
+  (concat "<a href=\"" (emacs-wiki-published-name url) "\">" name "</a>"))
+
+(defun emacs-wiki-markup-link ()
+  "Resolve the matched wiki-link into its ultimate <a href> form.
+Images used the <img> tag."
+  ;; avoid marking up urls that appear to be inside existing HTML
+  (when (and (not (eq (char-after (point)) ?\"))
+             (not (eq (char-after (point)) ?\>)))
+    (let* ((wiki-link (match-string 0))
+           (url (emacs-wiki-escape-html-string
+                 (emacs-wiki-link-url wiki-link)))
+           (name (emacs-wiki-escape-html-string
+                  (emacs-wiki-wiki-visible-name wiki-link))))
+      (if (null url)
+          (if (and emacs-wiki-serving-p
+                   (emacs-wiki-editable-p (emacs-wiki-wiki-base wiki-link)))
+              (concat "<a class=\"nonexistent\" href=\"editwiki?"
+                      (emacs-wiki-wiki-base wiki-link) "\">" name "</a>")
+            (concat "<a class=\"nonexistent\" href=\""
+                    emacs-wiki-maintainer "\">" name "</a>"))
+        (if (save-match-data
+              (string-match emacs-wiki-image-regexp url))
+            (concat "<img src=\"" url "\" alt=\"" name "\">")
+          (concat "<a href=\"" url "\">" name "</a>"))))))
+
+(defun emacs-wiki-markup-word ()
+  (let* ((beg (match-beginning 2))
+        (end (1- (match-end 2)))
+        (leader (buffer-substring-no-properties beg end))
+        open-tag close-tag mark-read-only loc multi-line)
+    (cond
+     ((string= leader "_")
+      (setq open-tag "<u>" close-tag "</u>"))
+     ((string= leader "=")
+      (setq open-tag "<code>" close-tag "</code>")
+      (setq mark-read-only t))
+     (t
+      (setq multi-line t)
+      (let ((l (length leader)))
+       (cond
+        ((= l 1) (setq open-tag "<em>" close-tag "</em>"))
+        ((= l 2) (setq open-tag "<strong>" close-tag "</strong>"))
+        ((= l 3) (setq open-tag "<strong><em>"
+                       close-tag "</em></strong>"))))))
+    (if (and (setq loc (search-forward leader nil t))
+             (eq 0 (skip-syntax-forward "w" (1+ loc)))
+             (or multi-line (= 1 (count-lines beg loc))))
+        (progn
+          (replace-match "")
+          (insert close-tag)
+          (save-excursion
+            (goto-char beg)
+            (delete-region beg end)
+            (insert open-tag))
+          (if mark-read-only
+              (add-text-properties beg (point)
+                                   '(rear-nonsticky (read-only) read-only
+                                   t))))
+      (backward-char))
+    nil))
+
+(defun emacs-wiki-markup-anchor ()
+  (save-match-data
+    (emacs-wiki-insert-anchor (match-string 1)))
+  "")
+
+(defcustom emacs-wiki-entity-table
+  '(("#7779" . "s")
+    ("#7717" . "h")
+    ("#7789" . "t")
+    ("#7716" . "H")
+    ("#7826" . "Z"))
+  "Substitutions to use for HTML entities which are not fully
+supported by all browsers -- in other words, we are pre-empting the
+entity mechanism and providing our own textual equivalent.  For
+Unicode browsers, this is usually unnecessary."
+  :type 'sexp
+  :group 'emacs-wiki)
+
+(defun emacs-wiki-markup-entity ()
+  (or (cdr (assoc (match-string 1)
+                 emacs-wiki-entity-table))
+      (concat "&" (match-string 1) ";")))
+
+(defsubst emacs-wiki-surround-text (beg-tag end-tag move-func)
+  (insert beg-tag)
+  (funcall move-func)
+  (insert end-tag))                    ; returns nil for us
+
+(defun emacs-wiki-markup-heading ()
+  (let ((len (1+ (length (match-string 1)))))
+    (emacs-wiki-surround-text (format "<h%d>" len) (format "</h%d>" len)
+                             'end-of-line)
+    ""))
+
+(defun emacs-wiki-markup-footnote ()
+  (if (/= (line-beginning-position) (match-beginning 0))
+      "<sup><a name=\"fnr.\\1\" href=\"#fn.\\1\">\\1</a></sup>"
+    (prog1
+       "<sup>[<a name=\"fn.\\1\" href=\"#fnr.\\1\">\\1</a>]</sup>"
+      (save-excursion
+       (save-match-data
+         (let* ((beg (goto-char (match-end 0)))
+                (end (and (search-forward "\n\n" nil t)
+                          (prog1
+                              (copy-marker (match-beginning 0))
+                            (goto-char beg)))))
+           (while (re-search-forward "^[ \t]+\\([^\n]\\)" end t)
+             (replace-match "\\1" t))))))))
+
+(defsubst emacs-wiki-forward-paragraph ()
+  (and (re-search-forward "^\\s-*$" nil t)
+       (match-beginning 0)))
+
+(defun emacs-wiki-markup-list-or-paragraph ()
+  "Markup a list entry or quoted paragraph.
+The reason this function is so funky, is to prevent text properties
+like read-only from being inadvertently deleted."
+  (if (null (match-string 2))
+      (let* ((ws (match-string 4))
+            (tag (if (>= (string-width ws) 6)
+                     "center"
+                   "blockquote")))
+       (unless (and (equal tag "blockquote")
+                    (save-excursion
+                      (forward-line)
+                      (or (eolp)
+                          (looking-at "\\S-"))))
+         (emacs-wiki-surround-text (format "<%s>\n<p>\n%s" tag ws)
+                                   (format "\n</p>\n</%s>\n" tag)
+                                   'emacs-wiki-forward-paragraph)))
+    (let ((str (match-string 2)))
+      (cond
+       ((and (eq (aref str 0) ?-))
+       (delete-region (match-beginning 0) (match-end 0))
+       (emacs-wiki-surround-text
+        "<ul>\n<li>" "</li>\n</ul>\n"
+        (function
+         (lambda ()
+           (and (re-search-forward "^\\s-*\\(-\\|$\\)" nil t)
+                (goto-char (match-beginning 0)))))))
+       ((and (>= (aref str 0) ?0)
+            (<= (aref str 0) ?9))
+       (delete-region (match-beginning 0) (match-end 0))
+       (emacs-wiki-surround-text
+        "<ol>\n<li>" "</li>\n</ol>\n"
+        (function
+         (lambda ()
+           (and (re-search-forward "^\\s-*\\([0-9]+\\.\\|$\\)" nil t)
+                (goto-char (match-beginning 0)))))))
+       (t
+       (goto-char (match-beginning 0))
+       (insert "<dl>\n<dt>")
+       (save-match-data
+         (when (re-search-forward "[ \t\n]+::[ \t\n]+" nil t)
+           (replace-match "</dt>\n<dd>\n")))
+       (emacs-wiki-forward-paragraph)
+       (insert "</dd>\n</dl>\n"))))))
+
+(defun emacs-wiki-markup-table ()
+  (if (featurep 'table)
+      (let ((leader (match-string 1))
+           (begin (copy-marker (match-beginning 0)))
+           table end)
+       (goto-char (match-end 0))
+       (setq table
+             (with-current-buffer (table-generate-source 'html)
+               (prog1
+                   (buffer-string)
+                 (kill-buffer (current-buffer)))))
+       (goto-char begin)
+       (if (re-search-backward "<p>[ \t\n\r]+" nil t)
+           (replace-match (if (>= (string-width leader) 6)
+                              "<center>\n"
+                            (if (> (length leader) 0)
+                                "<blockquote>\n"
+                              ""))))
+       (delete-region begin (re-search-forward "-+\\+\\s-*[\r\n]+\\s-*$"
+                                               nil t))
+       (insert table)
+       (setq end (point-marker))
+       (goto-char begin)
+       (while (< (point) end)
+         (if (looking-at "^\\s-+")
+             (replace-match ""))
+         (forward-line))
+       (goto-char end)
+       (if (re-search-forward "[ \t\n\r]+</p>" nil t)
+           (replace-match (if (>= (string-width leader) 6)
+                              "\n</center>"
+                            (if (> (length leader) 0)
+                                "\n</blockquote>"
+                              ""))))
+       (set-match-data (list begin begin begin begin))
+       nil)
+    (let* ((str (save-match-data
+                  (if (featurep 'xemacs)
+                      ;; more emacs divergence. :(
+                      (replace-in-string (match-string 1) " *|+ *$" "")
+                    (match-string 1))))
+           (fields
+            (append (save-match-data
+                      (split-string str "[ \t]*|+[ \t]*"))
+                   (list (match-string 4))))
+          (len (length (match-string 3)))
+          (row (cond ((= len 1) "tbody")
+                     ((= len 2) "thead")
+                     ((= len 3) "tfoot")))
+          (col (cond ((= len 1) "td")
+                     ((= len 2) "th")
+                     ((= len 3) "td"))))
+      (concat "<table " emacs-wiki-table-attributes ">\n"
+             "<" row ">\n" "<tr>\n<" col ">"
+             (mapconcat 'identity fields (format "</%s><%s>" col col))
+             "</" col ">\n" "</tr>\n" "</" row ">\n"
+             "</table>\n"))))
+
+(defun emacs-wiki-markup-verse ()
+  (save-match-data
+    (let* ((lines (split-string (match-string 1) "\n"))
+          (l lines))
+      (while l
+       (if (and (> (length (car l)) 2)
+                (string-match "\\`\\s-*> " (car l)))
+           (setcar l (substring (car l) (match-end 0))))
+       (setq l (cdr l)))
+      (concat "<p class=\"verse\">"
+             (mapconcat 'identity lines "\n") "</p>"))))
+
+(defcustom emacs-wiki-pretty-changelogs nil
+  "If non-nil, markup ChangeLog buffers using pretty tables.
+This rule requires that a GIF file called \"onepixel.gif\" be in your
+publication tree.  Here is a uuencoded version of such a file:
+
+begin 644 onepixel.gif
+M1TE&.#EA`0`!`*$``````/___________R'Y!`'__P$`+``````!``$```(\"
+$3`$`.P``
+`
+end"
+  :type 'boolean
+  :group 'emacs-wiki-publish)
+
+(defun emacs-wiki-changelog-escape-files ()
+  (replace-match "[[\\1]]" t nil nil 1))
+
+(defun emacs-wiki-markup-changelog-section ()
+  (if (not emacs-wiki-pretty-changelogs)
+      "* \\1 \\2"
+    (let ((email (match-string 2))
+         (date (match-string 1)))
+      (goto-char (match-beginning 0))
+      (delete-region (match-beginning 0) (match-end 0))
+      (while (eolp)
+       (kill-line 1))
+      (insert (format "  <TABLE WIDTH=\"100%%\" BORDER=\"0\"
+        CELLSPACING=\"1\" CELLPADDING=\"2\">
+    <TR>
+      <TD BGCOLOR=\"black\" BACKGROUND=\"onepixel.gif\">
+       <TABLE WIDTH=\"100%%\" BORDER=\"0\"
+              CELLPADDING=\"5\" CELLSPACING=\"0\">
+         <TR>
+           <TD ALIGN=\"left\" BGCOLOR=\"b0c4de\" BACKGROUND=\"onepixel.gif\">
+             <FONT COLOR=\"navy\"> <B>%s</B> </FONT>
+           </TD>
+           <TD ALIGN=\"right\" VALIGN=\"bottom\" BGCOLOR=\"b0c4de\"
+               BACKGROUND=\"onepixel.gif\">
+             <FONT SIZE=\"2\" COLOR=\"2f4f4f\"> %s </FONT>
+           </TD>
+         </TR>
+         <TR>
+           <TD BGCOLOR=\"fffff0\" COLSPAN=\"2\" BACKGROUND=\"onepixel.gif\">
+             <FONT COLOR=\"black\">
+" email date))
+      (add-text-properties (match-beginning 0) (point)
+                          '(read-only t rear-nonsticky (read-only))))
+    (if (re-search-forward "^[0-9]" nil t)
+       (goto-char (1- (match-beginning 0)))
+      (goto-char (point-max))
+      (while (eq (char-before (1- (point))) ?\n)
+       (delete-char -1)))
+    (let ((here (1- (point))))
+      (insert "
+             </FONT>
+           </TD>
+         </TR>
+       </TABLE>
+      </TD>
+    </TR>
+  </TABLE>
+  <br>")
+      (add-text-properties here (point)
+                          '(read-only t rear-nonsticky (read-only)))
+      nil)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Emacs Wiki HTTP Server (using httpd.el)
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defgroup emacs-wiki-http nil
+  "Options controlling the behaviour of the Emacs Wiki HTTP server.
+
+So, you want to run a Wiki server based on Emacs?  It's simple.
+First, you will need two other scripts: httpd.el and cgi.el.  Both of
+them can be downloaded from Eric Mardsen's page:
+
+  http://www.chez.com/emarsden/downloads/
+
+Once you have those two scripts, you must decide between two different
+methods of serving pages directly from Emacs:
+
+* PERSISTED INVOCATION SERVER
+
+This scheme keeps a dedicated Emacs process running, solely for the
+purpose of rendering pages.  It has the disadvantage of occupying
+virtual memory when no one is requesting pages.  It has the advantage
+of being 50 times faster than the next method.
+
+To use the persisted invoctaion server, you must download the Python
+script `httpd-serve' from the same website where you downloaded
+emacs-wiki:
+
+  http://www.gci-net.com/~johnw/emacs.html
+
+Once you have have downloaded the script, running it is simple:
+
+  ./httpd-serve --daemon --port 8080 --load /tmp/my-emacs-wiki \
+      [path to your HTML files]
+
+The file `/tmp/my-emacs-wiki.el' should contain all the customizations
+required by your Wiki setup.  This is how the server knows where to
+find your pages.  This script MUST contain the following line:
+
+  (load \"emacs-wiki\")
+
+That's it.  You should now be able to access your Wiki repository at
+localhost:8080.  Only world-readable will be visible, and only
+world-writable can be edited over HTTP.
+
+* AN EMACS SPAWNED PER REQUEST
+
+The old method of serving Wiki pages directly is to spawn an Emacs
+invocation for every request.  This has the advantage of being a far
+simpler approach, and it doesn't consume memory if no one is
+requesting pages.  The disadvantage is that it's hideously slow, and
+multiple requests may bog down your machine's supply of virtual
+memory.
+
+Anyway, to use this approach, add the following line to your
+/etc/inted.conf file:
+
+  8080 stream tcp nowait.10000 nobody /usr/local/bin/emacs-httpd
+
+The emacs-httpd script should look something like this:
+
+  #!/bin/sh
+  /usr/bin/emacs -batch --no-init-file --no-site-file \\
+      -l httpd -l cgi -l emacs-wiki \\
+      --eval \"(setq httpd-document-root emacs-wiki-publishing-directory \\
+                   emacs-wiki-maintainer \\\"mailto:joe@where.com\\\")\" \\
+      -f httpd-serve 2> /dev/null
+
+Emacs-wiki will now serve pages directly on port 8080.  Note that if
+you need to configure any variables in emacs-wiki, you will have to
+repeat those configurations in the emacs-httpd script.
+
+Note: If you have the 'stopafter' tool installed, it's a good idea to
+put a limit on how much time each Emacs process is allowed.  And if
+you want to render planner.el pages, you'll need to make another
+modification.  Here is a more complete example:
+
+  #!/bin/sh
+  /usr/bin/stopafter 60 KILL /usr/bin/emacs \\
+      -batch --no-init-file --no-site-file \\
+      -l httpd -l cgi -l emacs-wiki -l planner \\
+      --eval \"(progn \\
+        (setq httpd-document-root emacs-wiki-publishing-directory \\
+              emacs-wiki-maintainer \\\"mailto:joe@where.com\\\") \\
+        (planner-update-wiki-project))\" \\
+      -f httpd-serve 2> /dev/null"
+  :group 'emacs-wiki)
+
+(defcustom emacs-wiki-http-search-form
+  "
+<form method=\"GET\" action=\"/searchwiki?get\">
+  <center>
+    Search for: <input type=\"text\" size=\"50\" name=\"q\" value=\"\">
+    <input type=\"submit\" value=\"Search!\">
+  </center>
+</form>\n"
+  "The form presenting for doing searches when using httpd.el."
+  :type 'string
+  :group 'emacs-wiki-http)
+
+(defcustom emacs-wiki-http-support-editing t
+  "If non-nil, allow direct editing when serving over httpd.el.
+Note that a page can be edited only if it is world-writable and
+`emacs-wiki-use-mode-flags' is set, or if it matches one of the
+regexps in `emacs-wiki-editable-pages'."
+  :type 'boolean
+  :group 'emacs-wiki-http)
+
+(defcustom emacs-wiki-http-edit-form
+  "
+<form method=\"POST\" action=\"/changewiki?post\">
+  <textarea name=\"%PAGE%\" rows=\"25\" cols=\"80\">%TEXT%</textarea>
+  <center>
+    <input type=\"submit\" value=\"Submit changes\">
+  </center>
+</form>\n"
+  "The form presenting for doing edits when using httpd.el."
+  :type 'string
+  :group 'emacs-wiki-http)
+
+(defun emacs-wiki-http-send-buffer (&optional title modified code
+                                             msg no-markup)
+  "Markup and send the contents of the current buffer via HTTP."
+  (unless no-markup (emacs-wiki-replace-markup title))
+  (princ "HTTP/1.0 ")
+  (princ (or code 200))
+  (princ " ")
+  (princ (or msg "OK"))
+  (princ httpd-line-terminator)
+  (princ "Server: emacs-wiki.el/2.26")
+  (princ httpd-line-terminator)
+  (princ "Connection: close")
+  (princ httpd-line-terminator)
+  (princ "MIME-Version: 1.0")
+  (princ httpd-line-terminator)
+  (princ "Date: ")
+  (princ (format-time-string "%a, %e %b %Y %T %Z"))
+  (princ httpd-line-terminator)
+  (princ "From: ")
+  (princ (substring emacs-wiki-maintainer 7))
+  (when modified
+    (princ httpd-line-terminator)
+    (princ "Last-Modified: ")
+    (princ (format-time-string "%a, %e %b %Y %T %Z" modified)))
+  (princ httpd-line-terminator)
+  (princ "Content-Type: text/html; charset=iso-8859-1")
+  (princ httpd-line-terminator)
+  (princ "Content-Length: ")
+  (princ (1- (point-max)))
+  (princ httpd-line-terminator)
+  (princ httpd-line-terminator)
+  (princ (buffer-string)))
+
+(defun emacs-wiki-http-reject (title msg &optional annotation)
+  (with-temp-buffer
+    (insert msg ".\n")
+    (if annotation
+       (insert annotation "\n"))
+    (emacs-wiki-http-send-buffer title nil 404 msg)))
+
+(defvar emacs-wiki-buffer-mtime nil)
+(make-variable-buffer-local 'emacs-wiki-buffer-mtime)
+
+(defun emacs-wiki-sort-buffers (l r)
+  (let ((l-mtime (with-current-buffer l
+                  emacs-wiki-buffer-mtime))
+       (r-mtime (with-current-buffer r
+                  emacs-wiki-buffer-mtime)))
+    (cond
+     ((and (null l-mtime) (null r-mtime)) l)
+     ((null l-mtime) r)
+     ((null r-mtime) l)
+     (t (emacs-wiki-time-less-p r-mtime l-mtime)))))
+
+(defun emacs-wiki-winnow-list (entries &optional predicate)
+  "Return only those ENTRIES for which PREDICATE returns non-nil."
+  (let ((flist (list t))
+       valid p)
+    (let ((entry entries))
+      (while entry
+       (if (funcall predicate (car entry))
+           (nconc flist (list (car entry))))
+       (setq entry (cdr entry))))
+    (cdr flist)))
+
+(defcustom emacs-wiki-max-cache-size 64
+  "The number of pages to cache when serving over HTTP.
+This only applies if set while running the persisted invocation
+server.  See main documentation for the `emacs-wiki-http'
+customization group."
+  :type 'integer
+  :group 'emacs-wiki-http)
+
+(defun emacs-wiki-prune-cache ()
+  "If the page cache has become too large, prune it."
+  (let* ((buflist (sort (emacs-wiki-winnow-list
+                        (buffer-list)
+                        (function
+                         (lambda (buf)
+                           (with-current-buffer buf
+                             emacs-wiki-buffer-mtime))))
+                       'emacs-wiki-sort-buffers))
+        (len (length buflist)))
+    (while (> len emacs-wiki-max-cache-size)
+      (kill-buffer (car buflist))
+      (setq len (1- len)))))
+
+(defun emacs-wiki-render-page (name)
+  "Render the wiki page identified by NAME.
+When serving from a dedicated Emacs process (see the httpd-serve
+script), a maximum of `emacs-wiki-max-cache-size' pages will be cached
+in memory to speed up serving time."
+  (if (equal name emacs-wiki-index-page)
+      (with-current-buffer (emacs-wiki-generate-index t t)
+       (emacs-wiki-http-send-buffer "Wiki Index")
+       (kill-buffer (current-buffer)))
+    (let ((file (and (not (emacs-wiki-private-p name))
+                    (cdr (assoc name (emacs-wiki-file-alist)))))
+         (inhibit-read-only t))
+      (if (null file)
+         (emacs-wiki-http-reject "Page not found"
+                                 (format "Wiki page %s not found" name))
+       (set-buffer (get-buffer-create file))
+       (let ((modified-time (nth 5 (file-attributes file))))
+         (when (or (null emacs-wiki-buffer-mtime)
+                   (emacs-wiki-time-less-p emacs-wiki-buffer-mtime
+                                           modified-time))
+           (erase-buffer)
+           (setq emacs-wiki-buffer-mtime modified-time))
+         (goto-char (point-max))
+         (if (not (bobp))
+             (emacs-wiki-http-send-buffer nil emacs-wiki-buffer-mtime
+                                          nil nil t)
+           (insert-file-contents file t)
+           (cd (file-name-directory file))
+           (emacs-wiki-maybe)
+           (emacs-wiki-http-send-buffer nil emacs-wiki-buffer-mtime)))
+       (set-buffer-modified-p nil)
+       (emacs-wiki-prune-cache)))))
+
+(defun emacs-wiki-wikify-search-results (term)
+  "Convert the current buffer's grep results into a Wiki form."
+  (goto-char (point-max))
+  (forward-line -2)
+  (delete-region (point) (point-max))
+  (goto-char (point-min))
+  (kill-line 2)
+  (let ((results (list t)))
+    (while (re-search-forward "^.+/\\([^/:]+\\):\\s-*[0-9]+:\\(.+\\)" nil t)
+      (let ((page (match-string 1)))
+       (unless (or (emacs-wiki-private-p page)
+                   (string-match emacs-wiki-file-ignore-regexp page))
+         (let ((text (match-string 2))
+               (entry (assoc page results)))
+           (if entry
+               (nconc (cdr entry) (list text))
+             (nconc results (list (cons page (list text)))))))))
+    (delete-region (point-min) (point-max))
+    (setq results
+         (sort (cdr results)
+               (function
+                (lambda (l r)
+                  (string-lessp (car l) (car r))))))
+    (while results
+      (unless (emacs-wiki-private-p (caar results))
+       (insert "[[" (caar results) "]] ::\n  <p>")
+       (let ((hits (cdar results)))
+         (while hits
+           (while (string-match "</?lisp>" (car hits))
+             (setcar hits (replace-match "" t t (car hits))))
+           (while (string-match (concat "\\([^*?[/>]\\)\\<\\(" term "\\)\\>")
+                                (car hits))
+             (setcar hits (replace-match "\\1<strong>\\2</strong>"
+                                         t nil (car hits))))
+           (insert "  > <verbatim>" (car hits) "</verbatim>\n")
+           (setq hits (cdr hits))))
+       (insert "</p>\n\n"))
+      (setq results (cdr results)))))
+
+(defun emacs-wiki-setup-edit-page (page-name)
+  (insert "<verbatim>" emacs-wiki-http-edit-form "</verbatim>")
+  (goto-char (point-min))
+  (search-forward "%PAGE%")
+  (replace-match page-name t t)
+  (search-forward "%TEXT%")
+  (let ((beg (match-beginning 0))
+       (file (emacs-wiki-page-file page-name))
+       end)
+    (delete-region beg (point))
+    (when file
+      (insert-file-contents file)
+      (save-restriction
+       (narrow-to-region beg (point))
+       (goto-char (point-min))
+       (emacs-wiki-escape-html-specials)))))
+
+(defun emacs-wiki-http-changewiki (&optional content)
+  "Change the contents of Wiki page, using the results of a POST request."
+  (require 'cgi)
+  (unless content
+    (goto-char (point-min))
+    (if (not (re-search-forward "Content-length:\\s-*\\([0-9]+\\)" nil t))
+       (emacs-wiki-http-reject "Content-length missing"
+                               "No Content-length for POST request"
+                               (concat "Header received was:\n\n<example>"
+                                       (buffer-string) "</example>\n"))
+      (let ((content-length (string-to-number (match-string 1))))
+       (erase-buffer)
+       (read-event)                    ; absorb the CRLF separator
+       (let ((i 0))
+         (while (< i content-length)
+           (insert (read-event))
+           (setq i (1+ i))))))
+    (setq content (buffer-string)))
+  (when content
+    (let* ((result (cgi-decode content))
+          (page (caar result))
+          (text (cdar result))
+          (len (length text))
+          (require-final-newline t)
+          (pos 0) illegal user)
+      (if (not (emacs-wiki-editable-p page))
+         (emacs-wiki-http-reject
+          "Editing not allowed"
+          (format "Editing Wiki page %s is not allowed" page))
+       (while (and (null illegal)
+                   (setq pos (string-match "<\\s-*\\([^> \t]+\\)"
+                                           text pos)))
+         (setq pos (match-end 0))
+         (if (assoc (match-string 1 text) emacs-wiki-dangerous-tags)
+             (setq illegal (match-string 1 text))))
+       (if illegal
+           (emacs-wiki-http-reject
+            "Disallowed tag used"
+            (format "Public use of &lt;%s&gt; tag not allowed" illegal))
+         (emacs-wiki-find-file page)
+         (if (setq user (file-locked-p buffer-file-name))
+             (emacs-wiki-http-reject
+              "Page is locked"
+              (format "The page \"%s\" is currently being edited by %s."
+                      page (if (eq user t) (user-full-name) user)))
+           (let ((inhibit-read-only t)
+                 (delete-old-versions t))
+             (erase-buffer)
+             (insert (if (eq (aref text (1- len)) ?%)
+                         (substring text 0 (1- len))
+                       text))
+             (goto-char (point-min))
+             (while (re-search-forward "\r$" nil t)
+               (replace-match "" t t))
+             (save-buffer)
+             ;; this is 0666 - there is no read syntax for octals which
+             ;; works across all emacsen
+             (let ((oct 438))
+               (when (/= (file-modes buffer-file-name) oct)
+                 (set-file-modes buffer-file-name oct)))
+             (kill-buffer (current-buffer)))
+           (with-temp-buffer
+             (emacs-wiki-file-alist)   ; force re-check
+             (insert "<redirect url=\"" page "\" delay=\"3\">")
+             (insert "Thank you, your changes have been saved to " page)
+             (insert ".  You will be redirected to "
+                     "the new page in a moment.")
+             (insert "</redirect>")
+             (emacs-wiki-http-send-buffer "Changes Saved"))))))))
+
+(defvar httpd-vars nil)
+
+(defsubst httpd-var (var)
+  "Return value of VAR as a URL variable.  If VAR doesn't exist, nil."
+  (cdr (assoc var httpd-vars)))
+
+(defsubst httpd-var-p (var)
+  "Return non-nil if VAR was passed as a URL variable."
+  (not (null (assoc var httpd-vars))))
+
+(defun emacs-wiki-serve-page (page content)
+  (let ((handled t))
+    (cond
+     ((string-match "\\`wiki\\?\\(.+\\)" page)
+      (emacs-wiki-render-page (match-string 1 page)))
+
+     ((string-match "\\`editwiki\\?\\(.+\\)" page)
+      (let ((page-name (match-string 1 page)))
+       (if (not (emacs-wiki-editable-p page-name))
+           (emacs-wiki-http-reject "Editing not allowed"
+                                   "Editing this Wiki page is not allowed")
+         (with-temp-buffer
+           (emacs-wiki-setup-edit-page page-name)
+           ;; this is required because of the : in the name
+           (emacs-wiki-http-send-buffer
+            (concat "Edit Wiki Page: " page-name))))))
+
+     ((string-match "\\`searchwiki\\?get" page)
+      (with-temp-buffer
+       (insert "<verbatim>" emacs-wiki-http-search-form "</verbatim>")
+       (emacs-wiki-http-send-buffer "Search Wiki Pages")))
+
+     ((string-match "\\`searchwiki\\?q=\\(.+\\)" page)
+      (let ((compilation-scroll-output nil)
+           (term (match-string 1 page)))
+       (unintern 'start-process)
+       (require 'compile)
+       (with-current-buffer (emacs-wiki-grep term)
+         (emacs-wiki-wikify-search-results term)
+         (emacs-wiki-http-send-buffer "Search Results")
+         (kill-buffer (current-buffer)))))
+
+     ((string-match "\\`changewiki\\?post" page)
+      (emacs-wiki-http-changewiki content))
+
+     ((string-match "\\`diffwiki\\?\\(.+\\)" page)
+      ;; jww (2001-04-20): This code doesn't fully work yet.
+      (emacs-wiki-find-file (match-string 1 page))
+      (require 'vc)
+      (require 'vc-hooks)
+      (let ((curr-ver (vc-workfile-version buffer-file-name)))
+       (vc-version-diff buffer-file-name
+                        curr-ver (vc-previous-version curr-ver))
+       (let ((inhibit-read-only t))
+         (goto-char (point-min))
+         (when (re-search-forward "^diff" nil t)
+           (forward-line)
+           (delete-region (point-min) (point)))
+         (insert "<verbatim><pre>")
+         (emacs-wiki-escape-html-specials)
+         (goto-char (point-max))
+         (if (re-search-backward "^Process.*killed" nil t)
+             (delete-region (point) (point-max)))
+         (insert "</verbatim></pre>")
+         (emacs-wiki-http-send-buffer "Diff Results"))))
+
+     (t
+      (setq handled nil)))
+    handled))
+
+(defun emacs-wiki-serve (page &optional content)
+  "Serve the given PAGE from this emacs-wiki server."
+  ;; index.html is really a reference to the main Wiki page
+  (if (string= page "index.html")
+      (setq page (concat "wiki?" emacs-wiki-home-page)))
+
+  ;; handle the actual request
+  (let ((vc-follow-symlinks t)
+       (emacs-wiki-report-threshhold nil)
+       (emacs-wiki-serving-p t)
+       httpd-vars project)
+    (save-excursion
+      ;; process any CGI variables, if cgi.el is available
+      (if (string-match "\\`\\([^&]+\\)&" page)
+         (setq httpd-vars
+               (and (fboundp 'cgi-decode)
+                    (cgi-decode (substring page (match-end 0))))
+               page (match-string 1 page)))
+      (setq project (httpd-var "project"))
+      (if project
+         (with-emacs-wiki-project project
+           (emacs-wiki-serve-page page content))
+       (emacs-wiki-serve-page page content)))))
+
+(if (featurep 'httpd)
+    (httpd-add-handler "\\`\\(index\\.html\\|.*wiki\\(\\?\\|\\'\\)\\)"
+                      'emacs-wiki-serve))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Support for multile Emacs Wiki projects
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defgroup emacs-wiki-project nil
+  "Options controlling multi-project behavior in Emacs-Wiki."
+  :group 'emacs-wiki)
+
+(defvar emacs-wiki-current-project nil)
+(defvar emacs-wiki-predicate nil)
+(defvar emacs-wiki-major-mode nil)
+(defvar emacs-wiki-project-server-prefix nil)
+
+(defcustom emacs-wiki-show-project-name-p t
+  "When true, display the current project name in the mode-line"
+  :group 'emacs-wiki
+  :type 'boolean)
+
+;; this might go away - did anyone prefer the old behavior? tell me!
+(defvar emacs-wiki-old-project-change-p nil)
+
+(defcustom emacs-wiki-update-project-hook
+  '(emacs-wiki-update-project-interwikis)
+  "A hook called whenever `emacs-wiki-projects' is modified.
+By default, this hook is used to update the Interwiki table so that it
+contains links to each project name."
+  :type 'hook
+  :group 'emacs-wiki-project)
+
+(defun emacs-wiki-update-project-interwikis ()
+  (let ((projs emacs-wiki-projects))
+    (while projs
+      (add-to-list
+       'emacs-wiki-interwiki-names
+       `(,(caar projs)
+        . (lambda (tag)
+            (emacs-wiki-project-interwiki-link ,(caar projs) tag))))
+      (setq projs (cdr projs)))))
+
+(defcustom emacs-wiki-projects nil
+  "A list of project-specific Emacs-Wiki variable settings.
+Each entry is a cons cell, of the form (PROJECT VARS).
+
+Projects are useful for maintaining separate wikis that vary in
+some way. For instance, you might want to keep your work-related
+wiki files in a separate directory, with a different fill-column:
+
+(setq emacs-wiki-projects
+      `((\"default\" . ((emacs-wiki-directories . (\"~/wiki\"))))
+        (\"work\" . ((fill-column . 65)
+                 (emacs-wiki-directories . (\"~/workwiki/\"))))))
+
+You can then change between them with \\[emacs-wiki-change-project],
+by default bound to C-c C-v. When you use \\[emacs-wiki-find-file] to
+find a new file, emacs-wiki will attempt to detect which project it
+is part of by finding the first project where emacs-wiki-directories
+contains that file.
+
+VARS is an alist of symbol to value mappings, to be used locally in
+all emacs-wiki buffers associated with that PROJECT.
+
+You may also set the variable `emacs-wiki-predicate' in this alist,
+which should be a function to determine whether or not the project
+pertains to a certain buffer.  It will be called within the buffer in
+question.  The default predicate checks whether the file exists within
+`emacs-wiki-directories' for that project.
+
+The variable `emacs-wiki-major-mode' can be used to determine the
+major mode for a specific emacs-wiki buffer, in case you have
+developed a customized major-mode derived from `emacs-wiki-mode'.
+
+The variable `emacs-wiki-project-server-prefix' is prepended to the
+Interwiki URL, whenever an Interwiki reference to another project is
+made.  For example, if you had two projects, A and B, and in A you
+made a reference to B by typing B#WikiPage, A needs to know what
+directory or server to prepend to the WikiPage.html href.  If this
+variable is not set, it is assumed that both A and B publish to the
+same location.
+
+If any variable is not customized specifically for a project, the
+global value is used."
+  :type `(repeat
+         (cons
+          :tag "Emacs-Wiki Project"
+          (string :tag "Project name")
+          (repeat
+           (choice
+            (cons :tag "emacs-wiki-predicate"
+                  (const emacs-wiki-predicate) function)
+            (cons :tag "emacs-wiki-major-mode"
+                  (const emacs-wiki-major-mode) function)
+            (cons :tag "emacs-wiki-project-server-prefix"
+                  (const emacs-wiki-project-server-prefix) string)
+            ,@(mapcar
+               (function
+                (lambda (sym)
+                  (list 'cons :tag (symbol-name sym)
+                        (list 'const sym)
+                        (get sym 'custom-type))))
+               (apropos-internal "\\`emacs-wiki-"
+                                 (function
+                                  (lambda (sym)
+                                    (and (not (eq sym 'emacs-wiki-projects))
+                                         (get sym 'custom-type))))))))))
+  :set (function
+       (lambda (sym val)
+         (set sym val)
+         (run-hooks 'emacs-wiki-update-project-hook)))
+  :group 'emacs-wiki-project)
+
+(defmacro with-emacs-wiki-project (project &rest body)
+  "Evaluate as part of PROJECT the given BODY forms."
+  `(with-temp-buffer
+     (emacs-wiki-change-project ,project)
+     ,@body))
+
+(put 'with-emacs-wiki-project 'lisp-indent-function 1)
+
+(defun emacs-wiki-change-project (project)
+  "Manually change the project associated with the current buffer."
+  (interactive (list (completing-read "Switch to project: "
+                                     emacs-wiki-projects
+                                     nil t nil)))
+  (let ((projsyms (cdr (assoc project emacs-wiki-projects)))
+       sym)
+    (while projsyms
+      (setq sym (caar projsyms))
+      (unless (memq sym '(emacs-wiki-predicate emacs-wiki-major-mode))
+       (let ((custom-set (or (get sym 'custom-set) 'set))
+             (var (if (eq (get sym 'custom-type) 'hook)
+                      (make-local-hook sym)
+                    (make-local-variable sym))))
+         (if custom-set
+             (funcall custom-set var (cdar projsyms)))))
+      (setq projsyms (cdr projsyms))))
+  (when (not (string= emacs-wiki-current-project project))
+    ;; if it was a user request to change, change to the welcome buffer first
+    (if (and (interactive-p)
+               (not emacs-wiki-old-project-change-p))
+        (with-emacs-wiki-project
+         project (emacs-wiki-visit-link emacs-wiki-default-page))
+      (set (make-local-variable 'emacs-wiki-current-project) project)
+      (when emacs-wiki-show-project-name-p
+        (setq mode-name (concat "Wiki[" project "]"))))))
+
+(defun emacs-wiki-project-interwiki-link (project tag)
+  (with-emacs-wiki-project project
+    (if emacs-wiki-publishing-p
+       (concat emacs-wiki-project-server-prefix
+               (emacs-wiki-link-url (or tag emacs-wiki-home-page)))
+      (or (emacs-wiki-page-file (or tag emacs-wiki-home-page))
+         ;; doesn't yet exist, so we don't qualify the name, causing it to be
+         ;; rendered as a bad link
+         tag))))
+
+(provide 'emacs-wiki)
+;;; emacs-wiki.el ends here
diff --git a/emacs_el/mode-compile.el b/emacs_el/mode-compile.el
new file mode 100644 (file)
index 0000000..b83e1ba
--- /dev/null
@@ -0,0 +1,2648 @@
+;;; mode-compile.el ---  Smart command for compiling files
+;;                       according to major-mode.
+;;
+;;   Copyright (c) 1994 - 2003 heddy Boubaker C.E.N.A.
+;;
+;;   Author: Heddy Boubaker <heddy.Boubaker@cena.fr>
+;;   Maintainer: Heddy Boubaker <heddy.Boubaker@cena.fr>
+;;   Created: June 1994
+;;   Last modified: 2003/04/01 13:52:47
+;;   Version: 2.28
+;;   Keywords: compile, compilation, modes, languages
+;;   Tested for:
+;;     XEmacs (Lucid GNU Emacs) >= 19.10
+;;     Must work with FSF GNU Emacs > 19.31 ;-)
+;;     Do not work anymore for Emacses <= 18
+;;   Ftp access:
+;;    archive.cis.ohio-state.edu:pub/gnu/emacs/elisp-archive/misc/mode-compile.el.Z
+;;   WWW access:
+;;    <URL http://www.tls.cena.fr/~boubaker/Emacs/>
+;;
+;; LCD Archive Entry:
+;; mode-compile|Heddy Boubaker|boubaker@cena.fr|
+;; Smart command for compiling files according to major-mode and more.|
+;; 2003/04/01 13:52:47|2.28|~/misc/mode-compile.el.Z|
+;;
+;;; This file is NOT part of GNU Emacs but the same permissions apply.
+;;
+;; GNU Emacs is free software; you can redistribute  it and/or modify it under
+;; the terms  of  the GNU General   Public License as   published  by the Free
+;; Software Foundation;    either version 2,   or (at  your option)  any later
+;; version.
+;;
+;; GNU Emacs  is distributed in  the hope that it will  be useful, but WITHOUT
+;; ANY  WARRANTY; without  even the  implied   warranty of 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.
+;;
+;; @ Purpose:
+;; ==========
+;;
+;;  Provide `mode-compile' function as a replacement  for the use of `compile'
+;;  command which  is  very dumb  for  creating it's  compilation command (use
+;;  "make  -k" by default).  `mode-compile'  is  a layer  above `compile'; Its
+;;  purpose is mainly   to  build a  smart  compile-command for  `compile'  to
+;;  execute  it. This   compile-command is   built   according  to number   of
+;;  parameters:
+;;   - the major-mode.
+;;   - presence or not of a makefile in current directory.
+;;   - the buffer-file-name and extension.
+;;   - what is in the current buffer (`main' function,"#!/path/shell", ...).
+;;   - and more ... (see Commentary section below).
+;;  Most  of  these  parameters  are  higly customizable  throught Emacs  Lisp
+;;  variables  (to be  set  in your  .emacs  or  through Customization  menu).
+;;  Running  mode-compile after   an  universal-argument (C-u)  allows  remote
+;;  compilations, user is  prompted  for a host name   to run the  compilation
+;;  command on.   Another  function  provided  is  `mode-compile-kill'   which
+;;  terminate a running compilation session launched by `mode-compile'.
+;;
+;; @ Installation:
+;; ===============
+;;
+;;   Byte compile this file (*) somewhere in your `load-path' and add in
+;;  your .emacs:
+;;  (autoload 'mode-compile "mode-compile"
+;;   "Command to compile current buffer file based on the major mode" t)
+;;  (global-set-key "\C-cc" 'mode-compile)
+;;  (autoload 'mode-compile-kill "mode-compile"
+;;   "Command to kill a compilation launched by `mode-compile'" t)
+;;  (global-set-key "\C-ck" 'mode-compile-kill)
+;;
+;;  By  default mode-compile is  very verbose  and  waits a  few seconds (1 by
+;;  default) after  each message for   the user to have  time  to read it. You
+;;  could      set           variables      `mode-compile-expert-p'        and
+;;  `mode-compile-reading-time'   to  change  this    behaviour.  On X-Windows
+;;  systems  setting the variable  `mode-compile-other-frame-p'  will create a
+;;  new frame and launch the compilation command in it.
+;;
+;;  (*) Don't take care of messages:
+;;        ** reference to free variable efs-remote-shell-file-name
+;;      This is perfectly normal ;-}. But if you know a way to avoid it let me
+;;      know.
+;;
+;; @ Bug Reports:
+;; ==============
+;;
+;;   To   report a  bug  please  use function `mode-compile-submit-bug-report'
+;;   Please note that this bug-report facility uses Barry Warsaw's reporter.el
+;;   which is part of GNU Emacs v19 and bundled with many  other packages.  If
+;;   needed, you can obtain a copy of reporter.el at the elisp-archive.
+;;
+;; @ Documentation:
+;; ================
+;;
+;;  This section will explain how the `compile-command' are built according to
+;;  the `major-mode' and how to  customize it.  The major modes `mode-compile'
+;;  currently known are:
+;;   - c-mode, c++-mode, makefile-mode, dired-mode, ada-mode, emacs-lisp-mode,
+;;     lisp-interaction-mode, sh-mode, csh-mode, fundamental-mode,  text-mode,
+;;     indented-text-mode     compilation-mode,  fortran-mode,    c?perl-mode,
+;;     zsh-mode java-mode, tcl-mode, python-mode
+;;  For other modes a default behaviour is provided.
+;;
+;;  When    running    `mode-compile'  or     `mode-compile-kill'   the  hooks
+;;  `mode-compile-(before|after)-(compile|kill)-hook'  are   executed.     The
+;;  current   buffer   could   be      automaticaly    saved    if    variable
+;;  `mode-compile-always-save-buffer-p' is  set  to   `t'.  ALL  the  modified
+;;  buffers could  be automaticaly saved if variable `mode-compile-save-all-p'
+;;  is set to `t'.
+;;
+;; @@ fundamental-mode, text-mode, indented-text-mode & UNKNOWN MODES:
+;;    *** THIS IS TOO THE DEFAULT BEHAVIOR FOR UNKNOWN MODES ***
+;;    Try to guess what the file is by:
+;;   - 1st looking at it's name and extension (see variable
+;;     `mode-compile-filename-regexp-alist').
+;;   - 2nd looking at string "#!/path/shell" at first line to extract shell
+;;     to run the script with (see variable `mode-compile-shell-alist').
+;;   - 3rd looking at a makefile in current directory.
+;;   - then calling `compile' with the last compile command which is
+;;     asked to be edited by user ...
+;;   The `kill-compile' command is then bound dynamically (buffer-local).
+;;
+;; @@ compilation-mode:
+;;    Call `compile' with the last compile command.
+;;
+;; @@ makefile-mode:
+;;    The makefile is run with make throught `compile' (user is prompted
+;;   for        the        rule         to      run,      see         variable
+;;   `mode-compile-prefered-default-makerule'  to  see how  a   default choice
+;;   could be selected).
+;;
+;; @@ emacs-lisp-mode, lisp-interaction-mode:
+;;    If the buffer is a .el file byte-compile it to produce a .elc file,
+;;   else  just  byte-compile  the   buffer  (this   don't  use  `compile' but
+;;   `byte-compile').
+;;
+;; @@ dired-mode:
+;;   Find a makefile   in   the directory and  run    make with  it   (like in
+;;   makefile-mode),  else try  to byte-recompile  all .el   files olders than
+;;   their associated  .elc  files (unlike  `byte-recompile-directory' this is
+;;   not  recursive),  finally if  no  .el  files  are present ask compilation
+;;   command to  user by  calling  `default-compile'.  To  find  a  makefile a
+;;   regexp is provided which name is `mode-compile-makefile-regexp'.
+;;
+;; @@ sh-mode, csh-mode, zsh-mode:
+;;    Run "[cz]?sh" with debugging arguments as specified in
+;;   `[cz]?sh-dbg-flags' on the currently edited file.
+;;
+;; @@ c?perl-mode:
+;;    Run  file with "perl   -w"  (can step   throught errors  with  compile's
+;;    `next-error' command).
+;;
+;; @@ tcl-mode:
+;;    Run     file  with "wish"  (can     step  throught errors with compile's
+;;    `next-error' command).
+;;
+;; @@ c-mode, c++-mode:
+;;   First it try to see if there is a makefile in the directory, makefiles to
+;;   look for are  specified  by the variable  `mode-compile-makefile-regexp'.
+;;   If yes two cases could happen: there  is only one  makefile so use it, or
+;;   there is more  than one (sometimes when  you need to  write portable soft
+;;   you  could have  some makefiles by  system:  SunOs.make, HP.make ...), in
+;;   that case prompt to  user for choice  (with smart completion).   Once the
+;;   makefile has been selected  it extract the rules from  it and ask to user
+;;   to   choose  a   rule  to  make  (with  smart  completion,  see  variable
+;;   `mode-compile-prefered- default-makerule'  to  see  how  a default choice
+;;   could be selected).
+;;
+;;   There are some cases where no makefiles are  presents (YES I KNOW this is
+;;   bad  practice but you  sometimes have no  needs  to write a Makefile). In
+;;   that case the  function try  to build  the most intelligent   compilation
+;;   command by using the favourite  user C/C++ compiler: value of environment
+;;   variable "CC"  or "CXX"  or  first found,   in  the PATH,   of  compilers
+;;   specified in variable  `cc-compilers-list' or `c++-compilers-list'.  Then
+;;   it look for the  varenv "CFLAGS" of  "CXXFLAGS" to append to the compiler
+;;   command,        find            the     file         to          compile:
+;;   <name-of-the-file-to-compiled>.(c|cc|C|cpp)  (see    *)   and   ask   for
+;;   confirmation.  If  you  really trust mode-compile   will build  the right
+;;   command  and  want to  bypass confirmation  you  could  set the  variable
+;;   `mode-compile-never-edit-command-p' to t.
+;;
+;;   (*) How to find <name-of-the-file-to-compiled>:
+;;    In both case the command try to guess which file has to be compiled:
+;;   It's a trivial choice when current buffer file is a
+;;   .(c|C|cc|cpp... -any file with extension specified in
+;;   `cc-source-file-ext-list' or `c++-source-file-ext-list') file but
+;;   when it's a .(h|H|hh) file what to do?  The variable
+;;   `cc-companion-file-regexp' or `c++-companion-file-regexp' specify
+;;   how to find a .(c|C|cc|cpp...) file from a .(h|H|hh...); This is
+;;   done by appending .(c|C|cc|cpp) to
+;;   <filename-without-matching-regexp>.  In c-mode with default value
+;;   it produce:
+;;      file.h, file_[Pp].h -> file.c
+;;      I sometimes use files _p.h to indicate that the file is a private header
+;;      file for a .c file.
+;;   In c++-mode with default value it produce:
+;;      file.hh, file_[Pp].hh -> file.cc
+;;      I sometimes use files _p.cc to indicate that the file is a private header
+;;      file for a .cc file.
+;;   The output of compilation will be a
+;;   <name-of-the-file-to-compiled>.o file if no `main' function is
+;;   found inside or a <name-of-the-file-to-compiled> EXECUTABLE file
+;;   if `main' function found.
+;;
+;; @@ ada-mode:
+;;   Same  as c/c++-mode but  run Ada compiler on the  Ada file.  There are no
+;;   companion file and no way to find a main function in Ada.
+;;
+;; @@ fortran-mode:
+;;    Same as c-mode but run Fortran compiler on .[Ff](or)? files.
+;;
+;; @@ java-mode:
+;;    Same as c-mode but call "javac" without the -o option on .java files
+;;
+;; @@  python-mode:
+;;    Run file with "python" (can step throught errors with compile's
+;;    `next-error' command).
+;;
+;; @@  message-mode:
+;;    Run `message-send'.
+;;
+;; @ WhatsNew:
+;; ===========
+;;
+;;  Support for cperl-mode
+;;  Require cl 
+;;
+;; @ Contributors/Helpers:
+;; =======================
+;;
+;;   Adrian Aichner <aichner@ecf.teradyne.com>
+;;   "William A. Perkins" <wa_perkins@pnl.gov>
+;;   Bin Mu <mubin@DerivaTech.COM>
+;;   Gael MARZIOU <Gael_Marziou@grenoble.hp.com>
+;;   Christian Motschke <motschke@prosun.first.gmd.de>
+;;   boris <boris@cs.rochester.edu>
+;;   Edward Hartnett <ejh@larry.gsfc.nasa.gov>.
+;;   Hartmut MANZ <manz@intes-stuttgart.de>.
+;;   Henry Guillaume <henryg@tusc.com.au>.
+;;   Ian Young <imy@wcl-rs.bham.ac.uk>
+;;   Ilya Zakharevich <ilya@math.ohio-state.edu>.
+;;   Kevin Broadey <KevinB@bartley.demon.co.uk>.
+;;   Lawrence R. Dodd <dodd@roebling.poly.edu>.
+;;   Martin Jost <asictest@ztivax.zfe.siemens.de>.
+;;   Michael Welsh Duggan <md5i+@andrew.cmu.edu>.
+;;   Rolf EBERT <rolf@gundog.lbl.gov>.
+;;   Scott Hofmann <scotth@visix.com>.
+;;   Stefan Schoef <Stefan.Schoef@arbi.informatik.uni-oldenburg.de>.
+;;   John W. Harwell <ccjohnh@showme.missouri.edu> - JWH.
+;;
+;; @ ToDo:
+;; =======
+;;
+;;   Extending this to some others programming languages (modes).
+;;   Writting an Info documentation.
+;;   Contributors are greatly accepted (send me diffs and don't forget to
+;;   update documentation and all comments too please).
+;;   Maybe Using ange-ftp parse .netrc utilities for remote host and
+;;   user infos.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+\f
+
+;; @ Requirements ;;;
+
+;; mode-compile is not a replacement for compile
+;; it is just a layer above it.
+(require 'compile)
+;;; For Emacs-Lisp files compilations
+(require 'byte-compile "bytecomp")
+;;; For easy macros
+(require 'backquote)
+(require 'cl)
+(load-library "cl-macs")
+;; Pretty print elisp
+(require 'pp)
+;;; Setting obsolete vars
+(eval-and-compile
+  (condition-case ()
+      (require 'obsolete)
+    (error nil))
+  (if (and (featurep 'obsolete) (fboundp 'define-obsolete-variable-alias))
+      nil ;; We've got what we needed
+    (defmacro define-obsolete-variable-alias (old new)
+      (` (progn (defalias (, old) (, new))
+                (put (, old) 'byte-obsolete-variable (, new)))
+         ))))
+;;; For using custom - stolen from w3-cus.el -
+(eval-and-compile
+  (condition-case ()
+      (require 'custom)
+    (error nil))
+  (if (and (featurep 'custom) (fboundp 'custom-declare-variable))
+      nil ;; We've got what we needed
+    ;; We have the old custom-library, hack around it!
+    (defmacro defgroup (&rest args)
+      nil)
+    (defmacro defcustom (var value doc &rest args)
+      (` (defvar (, var) (, value) (, doc))))))
+
+;; Custom groups
+(defgroup compilation nil
+  "Compilations from within Emacs variables."
+  :link '(url-link :tag "Author's Emacs Page"
+                   "http://www.tls.cena.fr/~boubaker/Emacs/")
+  :group 'tools
+  :group 'development)
+(defgroup compilation-lang nil
+  "Language specific compilation options."
+  :group 'languages
+  :group 'compilation)
+(defgroup compilation-script nil
+  "Scripts compilation options."
+  :group 'compilation)
+(defgroup compilation-elisp nil
+  "Emacs developpement compilation options."
+  :group 'lisp
+  :group 'compilation)
+
+;; @ User variables ;;;
+;; @@ Common variables to mode-compile for all modes ;;;
+
+(defcustom mode-compile-modes-alist
+  '((c-mode                . (cc-compile        kill-compilation))
+    (java-mode             . (java-compile      kill-compilation))
+    (c++-mode              . (c++-compile       kill-compilation))
+    (ada-mode              . (ada-compile       kill-compilation))
+    (fortran-mode          . (f77-compile       kill-compilation))
+    (dired-mode            . (dired-compile     kill-compilation))
+    (emacs-lisp-mode       . (elisp-compile     keyboard-quit)) ; I'm SURE IT'S NOT the best way
+    (lisp-interaction-mode . (elisp-compile     keyboard-quit)) ; to kill a byte-compilation.
+    (makefile-mode         . (makefile-compile  kill-compilation))
+    (sh-mode               . (sh-compile        kill-compilation))
+    (csh-mode              . (csh-compile       kill-compilation))
+    (zsh-mode              . (zsh-compile       kill-compilation))
+    (perl-mode             . (perl-compile      kill-compilation))
+    (cperl-mode            . (perl-compile      kill-compilation))
+    (tcl-mode              . (tcl-compile       kill-compilation)) ; JWH
+    (python-mode           . (python-compile    kill-compilation)) ; BM
+    ;(message-mode          . (message-compile   kill-compilation))
+    (fundamental-mode      . (guess-compile     nil)) ; bound dynamically
+    (text-mode             . (guess-compile     nil)) ; itou
+    (indented-text-mode    . (guess-compile     nil)) ; itou
+    (compilation-mode      . (default-compile   kill-compilation)))
+  "Assoc list of compile/kill functions for some known modes.
+
+Each element look like (MODE . (COMPILE-FUNCTION KILL-FUNCTION))
+ `mode-compile' will call COMPILE-FUNCTION and `mode-compile-kill'
+ KILL-FUNCTION if current major-mode is MODE.
+
+If you want to add or modify a COMPILE-FUNCTION and it's associated
+KILL-FUNCTION for MODE and don't want to hack `mode-compile' you could
+do the following (it exists however a more subtle method for
+modifying, this is left as an exercice for the reader :-):
+ (defun my-mode-compile() ...)
+ (defun my-mode-compile-kill() ...)
+ (setq mode-compile-modes-alist
+       (append '((my-mode . (my-mode-compile my-mode-compile-kill)))
+               mode-compile-modes-alist))"
+  :type '(repeat
+          (cons :tag "Association: mode/compilation functions"
+                (function :tag "Mode")
+                (list :tag "Compilation functions"
+                      (choice :tag "Function to run the compilation"
+                              (function-item :tag "Default" :value default-compile)
+                              (function-item :tag "Guess" :value guess-compile)
+                              (function-item :tag "Emacs lisp byte compilation" :value elisp-compile)
+                              (function :tag "Your choice, take care..."))
+                      (choice :tag "Function to kill a running compilation"
+                              (function-item :tag "Just kill" :value kill-compilation)
+                              (const :tag "Nothing -- use with guess-compile --" :value nil)
+                              (function-item :tag "To use with elisp-compile" :value keyboard-quit)
+                              ;; This item could not be selected due to a custom (hum) feature ...
+                              (function :tag "Your choice, take care..." :value nil)))))
+  :group 'compilation)
+
+(defcustom mode-compile-filename-regexp-alist
+  ;; These could be in auto-mode-alist. But if you are like me
+  ;; and don't like these modes (prefear to edit these kind of
+  ;; files in text-mode) this is a nice way to compile them
+  ;; without to be bored with their associated modes.
+  '((mode-compile-makefile-regexp . makefile-mode)
+    ("\\.sh$"                     . sh-mode)
+    ("\\.csh$"                    . csh-mode)
+    ("\\.zsh$"                    . zsh-mode))
+  "Assoc list of major-modes for some filenames regexp.
+
+Each element look like (REGEXP . MODE) This variable is really similar
+to `auto-mode-alist' in the fact that it associate a MODE to a REGEXP
+matching a filename. The only differences is that you are not obliged
+to have the specified MODE available to use it (`guess-compile' use
+it), the MODE is only a pointer to an assoq in
+`mode-compile-modes-alist' to get the COMPILE-FUNCTION and the
+KILL-FUNCTION. The REGEXP could be a form wich evaluate to a string.
+
+To add a new filename regexp do the following:
+ (setq mode-compile-filename-regexp-alist
+       (append '((my-filename-regexp . some-mode-mode-compile-know)
+               mode-compile-modes-alist))"
+  :type '(repeat
+          (cons :tag "Association: filename/mode"
+           (choice :tag "Filename regexp match"
+            (regexp :tag "Regexp as a string")
+            (symbol :tag "Variable containing the regexp")
+            (sexp :tag "Form wich evaluate to a string"))
+           ;; I need to bind dynamicaly this with const, ideas??
+           ;;`(choice
+           ;; ,@(mapcar (lambda (x) `(const ,(car x))) mode-compile-modes-alist))))
+           (function :tag "Mode to use -- should be a valid assoq in mode-compile-modes-alist --")))
+  :group 'compilation)
+
+(defcustom mode-compile-shell-alist
+  '(("sh"     .  sh-mode)
+    ("csh"    .  csh-mode)
+    ("zsh"    .  zsh-mode)
+    ("perl"   .  perl-mode)
+    ("tcl"    .   tcl-mode) ; JWH
+    ("python" . python-mode)) ; BM
+  "Assoc list of compile function for some known shells.
+
+Each element look like (SHELL . MODE) This variable look like
+`auto-mode-alist' in the fact that it associate a MODE to a name; A
+SHELL name here. The main difference is that you are not obliged to
+have the specified MODE available to use it (`guess-compile' use it),
+the MODE is only a pointer to an assoq in `mode-compile-modes-alist'
+to get the COMPILE-FUNCTION and the KILL-FUNCTION.
+
+To add a new shell do the following:
+ (setq mode-compile-filename-shell-alist
+       (append '((my-shell-name . some-mode-mode-compile-know)
+               mode-compile-modes-alist))"
+  :type '(repeat
+          (cons :tag "Association: shell name/mode"
+           (string :tag "Shell name")
+           ;; I need to bind dynamicaly this with const, ideas??
+           ;;`(choice
+           ;; ,@(mapcar (lambda (x) `(const ,(car x))) mode-compile-modes-alist))))
+           (function :tag "Mode to use -- should be a valid assoq in mode-compile-modes-alist --")))
+  :group 'compilation)
+
+;;;###autoload
+(defcustom mode-compile-make-program "make"
+  "*The `make' program used to process makefiles.
+
+If you have GNU make installed with name \"gmake\" use it."
+  :type 'string
+  :group 'compilation)
+
+(defcustom mode-compile-makefile-regexp
+  "\\(^[Mm]akefile\\|.*\\.[mM][aA]?[kK][eE]?\\.?.*$\\)"
+  "Regexp matching 'could be' makefiles filenames."
+  :type 'regexp
+  :group 'compilation)
+
+(defcustom mode-compile-makefile-backups-regexp
+  "\\(\\(~\\|\\.[bB][aA][cC]?[kK]\\)$\\)\\|\\(\\(^\\|/\\)[.,][^/]+$\\)"
+  "Regexp to find if a Makefile is a backup or not"
+  :type 'regexp
+  :group 'compilation)
+
+;;;###autoload
+(defcustom mode-compile-ignore-makefile-backups t
+  "*Tell mode compile to ignore makefiles backup files when selecting the Makefile to use."
+  :type 'boolean
+  :group 'compilation)
+
+;;;###autoload
+(defvar mode-compile-default-make-options "-k"
+  "Default options to give to `make'.")
+;;;###autoload
+(defcustom mode-compile-make-options (eval mode-compile-default-make-options)
+  "*Options to give to `make'.
+This could be any form evaluating to a string.
+
+Some people asked me a way to modify the make options everytime a
+compilation command is launched, do that:
+ (defun my-mode-compile-ask-make-options()
+   \"*Hook called by mode-compile, asking for make options.\"
+   (interactive)
+   (read-string \"Make options: \"
+                mode-compile-default-make-options))
+ (setq mode-compile-make-options
+           'my-mode-compile-ask-make-options)"
+  :type '(choice
+          string
+          (sexp :tag "Form evaluating to a string"))
+  :group 'compilation)
+
+;;;###autoload
+(defcustom mode-compile-prefered-default-makerule 'none
+  "*Default makerule you would like to see in minibuffer as a default choice
+when selecting the make rule to build.
+
+Possible values are:
+'none    -- let mode-compile deciding for you.
+'all     -- try hard to show you the \"all\" rule.
+'default -- try hard to show you the \"default\" rule.
+'file    -- try to show you the name of the file which will be
+            result of compilation.
+The 'none action is taken as default is something fail."
+  :type '(radio :tag "Symbol"
+                (const :tag "None - Let mode compile made the choice" :value none)
+                (const :tag "All - Show the \"all\" rule" :value all)
+                (const :tag "Default - Show the \"default\" rule" :value default)
+                (const :tag "File - Show the \"result file name\" rule" :value file))
+  :group 'compilation)
+
+;;;###autoload
+(defcustom mode-compile-ignore-makerule-regexp nil
+  "*Makefile rules which must be ignored when building completion list.
+
+For example if you want to remove all `files rules' set
+it to: \"\\\\.\\\\([aoc]\\\\|s[ao][.0-9]*\\\\)\". "
+  :type '(choice (const :tag "none" :value nil)
+                 (const :tag "The `all files' rule" :value "\\.\\([aoc]\\|s[ao][.0-9]*\\)")
+                 regexp)
+  :group 'compilation)
+
+;;;###autoload
+(defcustom mode-compile-save-all-p nil
+  "*Non-nil means save ALL the modified buffers without asking
+before launching compilation command."
+  :type 'boolean
+  :group 'compilation)
+
+;;;###autoload
+(defcustom mode-compile-always-save-buffer-p nil
+  "*Non-nil means save the current buffer without asking
+before launching compilation command."
+  :type 'boolean
+  :group 'compilation)
+
+;;;###autoload
+(defcustom mode-compile-never-edit-command-p nil
+  "*Non-nil means never ask to user to edit the compile command."
+  :type 'boolean
+  :group 'compilation)
+
+;; @@ Compilation in other frame vars ;;;
+(defgroup compilation-frame nil
+  "Compile in another frame variables."
+  :group 'frames
+  :group 'compilation)
+
+;;;###autoload
+(defcustom mode-compile-other-frame-p nil
+  "*Non-nil means compile in another frame.
+
+A new Emacs FRAME is created and the compilation command is executed
+in this other frame.  To specify the frame parameters see also
+variable `mode-compile-frame-parameters-alist'."
+  :type 'boolean
+  :group 'compilation-frame)
+
+(defcustom mode-compile-other-frame-name "COMPILATION"
+  "Name of mode-compile's other frame.
+
+This name could be used in your .Xdefault or .Xresources file as:
+Emacs.MODE-COMPILE-OTHER-FRAME-NAME.resource_to_be_set: ..."
+  :type 'string
+  :group 'compilation-frame)
+
+(defconst mode-compile-default-frame-parameters
+  (list
+   (cons 'name   mode-compile-other-frame-name)
+   (cons 'width  85)  ; columns
+   (cons 'height 30)) ; lines
+   "Default parameters for mode-compile's other frame.")
+
+(defvar mode-compile-frame-parameters-alist
+  (purecopy mode-compile-default-frame-parameters)
+  "Parameters for the new Compilation Screen created
+if variable `mode-compile-other-frame-p' is non nil..
+
+See also variable `mode-compile-default-frame-parameters' and
+`mode-compile-other-frame-name'.
+
+For informations about Screen/Frame parameters see:
+- Info, Nodes: Lispref::Screen::Screen Parameters
+- GNU Emacs Lisp Reference Manual, chapter 26 p375: Frames.")
+
+;; @@ Hooks ;;;
+
+;;;###autoload
+(defcustom mode-compile-before-compile-hook nil
+  "Hook to be run before compile command is executed
+when `mode-compile' is invoked."
+  :type 'hook
+  :group 'compilation)
+
+;;;###autoload
+(defcustom mode-compile-after-compile-hook nil
+  "Hook to be run after compile command is executed
+when `mode-compile' is invoked."
+  :type 'hook
+  :group 'compilation)
+
+;;;###autoload
+(defcustom mode-compile-before-kill-hook nil
+  "Hook to be run before killing compile command is executed
+when `mode-compile-kill' is invoked."
+  :type 'hook
+  :group 'compilation)
+
+;;;###autoload
+(defcustom mode-compile-after-kill-hook nil
+  "Hook to be run after killing compile command is executed
+when `mode-compile-kill' is invoked."
+  :type 'hook
+  :group 'compilation)
+
+;; @@ System dependencies ;;;
+
+(defvar mode-compile-exe-file-ext
+  (cond
+   ((memq system-type '(ms-dos emx windows-95 windows-98 windows-nt)) ".exe")
+   (t ""))
+  "*Extension of executable files (with dot included)")
+
+(defvar mode-compile-dir-separator-char
+  (cond
+   ;; MSDOSish file systems
+   ((memq system-type '(ms-dos emx windows-95 windows-98 windows-nt)) "\\")
+   ;; Unixish file systems
+   (t "/"))
+  "*Separator char between directories")
+
+;; @@ Facilities variables ;;;
+
+;;;###autoload
+(defvar mode-compile-choosen-compiler nil
+  "*Global variable containing the name of the compiler
+which will be used for compiling without makefile.
+
+ Could be used in combination with
+ (cc|c++|ada|f77)-default-compiler-options
+to automaticaly choose the compiler specific options.
+
+example:
+ (defun my-compiler-get-options()
+   (cond
+    ((string= mode-compile-choosen-compiler \"gcc\")
+      \"-Wall -pedantic-errors\")
+    ((string= mode-compile-choosen-compiler \"cc\")
+      \"cc options whatever they are...\")
+    (t
+     (message \"Don't know this compiler: %s\" mode-compile-choosen-compiler)
+     (read-string
+      (format \"Options for %s compiler: \" mode-compile-choosen-compiler)))))
+
+  (setq cc-default-compiler-options 'my-compiler-get-options)")
+
+;; @@ User level ;;;
+
+;;;###autoload
+(defcustom mode-compile-expert-p nil
+  "*Non nil means `mode-compile' will not speaks too much.
+
+See also variable variable mode-compile-reading-time."
+  :type 'boolean
+  :group 'compilation)
+
+;;;###autoload
+(defcustom mode-compile-reading-time 1
+  "*Seconds to wait in verbose mode after printing a message.
+
+In verbose mode mode-compile print too much messages that it is
+allmost impossible to read them. Just setting this delay leave you the
+time to read all the messages. If you don't want any delay set it to
+`0'.
+
+See also function sit-for."
+  :type 'integer
+  :group 'compilation)
+\f
+
+;; @@ Remote compilation vars ;;;
+(defgroup compilation-remote nil
+  "Remote compilations options."
+  :group 'compilation)
+
+(defcustom mode-compile-remote-hosts-alist '()
+  "Alist of favourites hosts names and the username
+to use to log on (HOSTNAME . USERNAME).
+
+If USERNAME is a function it will be called with HOSTNAME as argument
+and should return an USERNAME string (for example you could use
+something like efs-get-user - not tested -), if it is nil the function
+user-login-name will be used."
+  :type '(repeat
+          (cons
+           (string :tag "Hostname")
+           (choice
+            (const :tag "We'll use \'user-login-name" :value nil)
+            (string :tag "Username")
+            (function :tag "Function which return USERNAME given a HOSTNAME" :value efs-get-user))))
+  :group 'compilation-remote)
+
+(defcustom mode-compile-remote-execute-command "rsh"
+  "The shell command used to run a command remotely.
+\"rsh\" is the only choice I know but I'm far to know everything...
+
+ This variable is set automaticaly with the value of
+remote-shell-program or efs-remote-shell-file-name at load time."
+  :type 'string
+  :group 'compilation)
+(eval-when 'load
+  (cond
+   ((not (string= mode-compile-remote-execute-command "rsh"))
+    ;; user changed default
+    nil)
+   ;; Try to not multiply definitions of the same stuff
+   ;; in too many emacs lisp packages ...
+   ((and (boundp 'remote-shell-program) remote-shell-program)
+    (setq mode-compile-remote-execute-command remote-shell-program))
+   ((and (boundp 'efs-remote-shell-file-name) efs-remote-shell-file-name)
+    (setq mode-compile-remote-execute-command efs-remote-shell-file-name))
+   ))
+
+(defcustom mode-compile-remote-execute-set-host-arg ""
+  "Argument To set the remote host name to the
+mode-compile-remote-execute-command,
+
+None is required for \"rsh\"."
+  :type 'string
+  :group 'compilation-remote)
+
+(defcustom mode-compile-remote-execute-set-command-arg ""
+  "Argument to set the command to be run remotely to the
+mode-compile-remote-execute-command.
+
+None is required for \"rsh\"."
+  :type 'string
+  :group 'compilation-remote)
+
+(defcustom mode-compile-remote-execute-set-username-arg "-l"
+  "Argument to set the username under which we will log on
+on the remote host, to give to mode-compile-remote-execute-command."
+  :type 'string
+  :group 'compilation-remote)
+
+(defcustom mode-compile-remote-execute-misc-args ""
+  "Misc additionnals arguments to give to the
+mode-compile-remote-execute-command."
+  :type 'string
+  :group 'compilation-remote)
+
+\f
+
+;; @@ c-mode compile variables ;;;
+(defgroup compile-c nil
+  "C Compilation options."
+  :group 'c
+  :group 'compilation-lang)
+
+(defcustom cc-compilers-list '( "gcc" "c89" "acc" "cc" )
+  "List of user's favourites C compilers in order of preferencies."
+  :type '(repeat (string :tag "C Compiler name"))
+  :group 'compile-c)
+
+(defcustom cc-companion-file-regexp "\\(_[Pp]\\)?\\.[pP]?h"
+  "Regexp to find associated .c file from a .h."
+  :type 'regexp
+  :group 'compile-c)
+
+(defcustom cc-default-compiler "cc"
+  "*Default C compiler to use when everything else fails.
+
+This could be any form evaluating to a string, so you could map it to
+a function asking you interactively to choose the compiler.
+
+example:
+ (defun my-choose-compiler()
+   (read-string \"C compiler: \"))
+ (setq cc-compilers-list '()
+       cc-default-compiler 'my-choose-compiler)"
+  :type '(choice string function)
+  :group 'compile-c)
+
+(defcustom cc-compiler-varenv "CC"
+  "Varenv indicating the C compiler to use."
+  :type 'string
+  :group 'compile-c)
+
+(defcustom cc-cflags-varenv "CFLAGS"
+  "Varenv indicating the C compiler flags to use."
+  :type 'string
+  :group 'compile-c)
+
+(defcustom cc-source-ext-list '( "c" )
+  "Extensions for C compileable source files."
+  :type '(repeat string)
+  :group 'compile-c)
+
+(defcustom cc-headers-ext-list '( "h" )
+  "Extensions for C headers source files."
+  :type '(repeat string)
+  :group 'compile-c)
+
+(defcustom cc-default-compiler-options "-g"
+  "*Default options to give to the C compiler.
+
+This could be any form evaluating to a string.
+See `mode-compile-choosen-compiler' variable."
+  :type '(choice
+          string
+          (sexp :tag "Form evaluating to a string"))
+  :group 'compile-c)
+
+(defcustom cc-source-file-ext-regexp "\\.c"
+  "Regexp to find, from it's name, if a C file is compileable."
+  :type 'string
+  :group 'compile-c)
+
+(defcustom cc-build-output-args t
+  "Build output-args for c-mode."
+  :type 'boolean
+  :group 'compile-c)
+
+(defcustom cc-object-file-ext "o"
+  "Extension of objects file (result of compilation)
+in c mode."
+  :type 'string
+  :group 'compile-c)
+
+\f
+
+;; @@ java-mode compile variables ;;;
+(defgroup compile-java nil
+  "Java compilation options."
+  :group 'compilation-lang)
+
+(defcustom java-compilers-list '( "javac" )
+  "List of user's favourites java compilers in order of preferencies."
+  :type '(repeat (string :tag "Java Compiler name"))
+  :group 'compile-java)
+
+(defcustom java-companion-file-regexp ""
+  "Regexp to find associated compileable Java companion file.
+
+This is useless in Java because there do not exists uncompileable files."
+  :type 'regexp
+  :group 'compile-java)
+
+(defcustom java-default-compiler "javac"
+  "*Default C compiler to use when everything else fails.
+
+This could be any form evaluating to a string, so you could map it to
+a function asking you interactively to choose the compiler.
+
+example:
+ (defun my-choose-compiler()
+   (read-string \"Java compiler: \"))
+ (setq java-default-compiler 'my-choose-compiler)."
+  :type '(choice string function)
+  :group 'compile-java)
+
+(defcustom java-compiler-varenv "JAVAC"
+  "Varenv indicating the C compiler to use."
+  :type 'string
+  :group 'compile-java)
+
+(defcustom java-cflags-varenv "JAVAC_FLAGS"
+  "Varenv indicating the C compiler flags to use."
+  :type 'string
+  :group 'compile-java)
+
+(defcustom java-source-ext-list '( "java" )
+  "Extensions for Java compileable source files."
+  :type '(repeat string)
+  :group 'compile-java)
+
+(defcustom java-headers-ext-list '( "java" )
+  "Extensions for Java source files."
+  :type '(repeat string)
+  :group 'compile-java)
+
+(defcustom java-default-compiler-options "-O"
+  "*Default options to give to the Java compiler.
+
+This could be any form evaluating to a string.  See
+`mode-compile-choosen-compiler' variable."
+  :type '(choice
+          string
+          (sexp :tag "Form evaluating to a string"))
+  :group 'compile-java)
+
+(defcustom java-source-file-ext-regexp "\\.java"
+  "Regexp to find, from it's name, if a Java file is compileable."
+  :type 'regexp
+  :group 'compile-java)
+
+(defcustom java-build-output-args nil
+  "Dont build output-args for Java-mode."
+  :type 'boolean
+  :group 'compile-java)
+
+(defcustom java-object-file-ext "class"
+  "Extension of objects file (result of compilation)
+in java mode."
+  :type 'string
+  :group 'compile-java)
+
+\f
+
+;; @@ c++-mode compile variables ;;;
+(defgroup compile-c++ nil
+  "C++ compilation options"
+  :group 'compilation-lang)
+
+(defcustom c++-compilers-list '( "g++" "gcc" "CC" )
+  "List of user's favourites C++ compilers in order of preferencies."
+  :type '(repeat (string :tag "C++ Compiler name"))
+  :group 'compile-c++)
+
+(defcustom c++-companion-file-regexp "\\(_[Pp]\\)?\\.\\([pP]?[Hh][Hh]?\\|[Hh]\\+\\+?\\)"
+  "Regexp to find associated compileable C++ companion file
+from a header file."
+  :type 'regexp
+  :group 'compile-c++)
+
+(defcustom c++-default-compiler "CC"
+  "*Default C++ compiler to use when everything else fails..
+
+This could be any form evaluating to a string, so you could map it to
+a function asking you interactively to choose the compiler.
+
+example:
+ (defun my-choose-compiler()
+   (read-string \"C++ compiler: \"))
+ (setq c++-default-compiler 'my-choose-compiler)"
+  :type '(choice string function)
+  :group 'compile-c++)
+
+(defcustom c++-compiler-varenv "CXX"
+  "Varenv indicating the C++ compiler to use."
+  :type 'string
+  :group 'compile-c++)
+
+(defcustom c++-cflags-varenv "CXXFLAGS"
+  "Varenv indicating the C++ compiler flags to use."
+  :type 'string
+  :group 'compile-c++)
+
+(defcustom c++-source-ext-list '( "cc" "C" "CC" "cpp" "cxx" "c++" "c+" )
+  "Extensions for C++ compileable source files."
+  :type '(repeat string)
+  :group 'compile-c++)
+
+(defcustom c++-headers-ext-list '( "H" "hh" "HH" "h++" "h+" "h" "hpp" "hxx" )
+  "Extensions for C++ headers source files."
+  :type '(repeat string)
+  :group 'compile-c++)
+
+(defcustom c++-default-compiler-options "-g"
+  "*Default options to give to the C++ compiler.
+This could be any form evaluating to a string.  See
+`mode-compile-choosen-compiler' variable."
+  :type '(choice
+          string
+          (sexp :tag "Form evaluating to a string"))
+  :group 'compile-c++)
+
+(defcustom c++-source-file-ext-regexp "\\.\\(cc\\|CC?\\|c\\+\\+?\\|cpp\\|cxx\\)"
+  "Regexp to find, from it's name, if a C++ file is compileable."
+  :type 'regexp
+  :group 'compile-c++)
+
+(defcustom c++-build-output-args t
+  "Build output-args for c++-mode."
+  :type 'boolean
+  :group 'compile-c++)
+
+(defcustom c++-object-file-ext "o"
+  "Extension of objects file (result of compilation)
+in c++ mode."
+  :type 'string
+  :group 'compile-c++)
+
+\f
+
+;; @@ ada-mode compile variables ;;;
+(defgroup compile-ada nil
+  "Ada compilation options"
+  :group 'compilation-lang)
+
+(defcustom ada-compilers-list
+  '( "gcc" "gnat" "ada" )
+  "List of user's favourites Ada compilers in order of preferencies."
+  :type '(repeat (string :tag "Ada Compiler name"))
+  :group 'compile-ada)
+
+(defcustom ada-companion-file-regexp ""
+  "Regexp to find associated compileable Ada companion file from a spec file.
+
+This is useless in Ada because there do not exists uncompileable files."
+  :type 'regexp
+  :group 'compile-ada)
+
+(defcustom ada-default-compiler "ada"
+  "*Default Ada compiler to use when everything else fails.
+
+This could be any form evaluating to a string, so you could map it to
+a function asking you interactively to choose the compiler.
+
+example:
+ (defun my-choose-compiler()
+   (read-string \"Ada compiler: \"))
+ (setq ada-default-compiler 'my-choose-compiler)"
+  :type '(choice string function)
+  :group 'compile-ada)
+
+(defcustom ada-compiler-varenv "ADA"
+  "Varenv indicating the Ada compiler to use."
+  :type 'string
+  :group 'compile-ada)
+
+(defcustom ada-aflags-varenv "AFLAGS"
+  "Varenv indicating the Ada compiler flags to use."
+  :type 'string
+  :group 'compile-ada)
+
+(defcustom ada-source-ext-list '( "ads" "adb" "ada" "a" )
+  "Extensions for Ada compileable source files."
+  :type '(repeat string)
+  :group 'compile-ada)
+
+(defcustom ada-headers-ext-list '( "ads" "ada" "a" )
+  "Extensions for Ada spec source files."
+  :type '(repeat string)
+  :group 'compile-ada)
+
+(defcustom ada-default-compiler-options "-g"
+  "*Default options to give to the Ada compiler.
+
+This could be any form evaluating to a string.  See
+`mode-compile-choosen-compiler' variable."
+  :type '(choice
+          string
+          (sexp :tag "Form evaluating to a string"))
+  :group 'compile-ada)
+
+(defcustom ada-source-file-ext-regexp "\\.\\(ad[abs]\\|a\\)"
+  "Regexp to find, from it's name, if an Ada file is compileable.
+
+This is useless in Ada because there do not exists uncompileable files."
+  :type 'regexp
+  :group 'compile-ada)
+
+(defcustom ada-build-output-args t
+  "Build output-args for ada-mode."
+  :type 'boolean
+  :group 'compile-ada)
+
+(defcustom ada-object-file-ext "o"
+  "Extension of objects file (result of compilation)
+in ada mode."
+  :type 'string
+  :group 'compile-ada)
+
+\f
+
+;; @@ fortran-mode compile variables ;;;
+(defgroup compile-fortran nil
+  "Fortran compilation options"
+  :group 'compilation-lang)
+
+(defcustom f77-compilers-list '( "f77" "fc" )
+  "List of user's favourite Fortran compilers in order of preferencies."
+  :type '(repeat (string :tag "C Compiler name"))
+  :group 'compile-fortran)
+
+(defcustom f77-companion-file-regexp "\\(_[Pp]\\)?\\.[pP]?inc"
+  "Regexp to find associated .f file from a .inc."
+  :type 'regexp
+  :group 'compile-fortran)
+
+(defcustom f77-default-compiler "f77"
+  "*Default fortran compiler to use when everything else fails..
+
+This could be any form evaluating to a string, so you could map it to
+a function asking you interactively to choose the compiler.
+
+example:
+ (defun my-choose-compiler()
+   (read-string \"Fortran compiler: \"))
+ (setq f77-default-compiler 'my-choose-compiler)"
+  :type '(choice string function)
+  :group 'compile-fortran)
+
+(defcustom f77-compiler-varenv "F77"
+  "Varenv indicating the fortran compiler to use."
+  :type 'string
+  :group 'compile-fortran)
+
+(defcustom f77-cflags-varenv "FCOPTS"
+  "Varenv indicating the fortran compiler flags to use."
+  :type 'string
+  :group 'compile-fortran)
+
+(defcustom f77-source-ext-list '( "f" "F" "for" "For" )
+  "Extensions for fortran compileable source files."
+  :type '(repeat string)
+  :group 'compile-fortran)
+
+(defcustom f77-headers-ext-list '( "inc" "h")
+  "Extensions for fortran include files."
+  :type '(repeat string)
+  :group 'compile-fortran)
+
+(defcustom f77-default-compiler-options "-w66 -a"
+  "*Default options to give to the fortran compiler.
+
+This could be any form evaluating to a string.  See
+`mode-compile-choosen-compiler' variable."
+  :type '(choice
+          string
+          (sexp :tag "Form evaluating to a string"))
+  :group 'compile-fortran)
+
+(defcustom f77-source-file-ext-regexp "\\.\\([Ff]\\|for\\)"
+  "Regexp to find, from it's name, if a fortran file is compileable."
+  :type 'regexp
+  :group 'compile-fortran)
+
+(defcustom f77-build-output-args t
+  "Build output-args for f77-mode."
+  :type 'boolean
+  :group 'compile-fortran)
+
+(defcustom f77-object-file-ext "o"
+  "Extension of objects file (result of compilation)
+in Fortran mode."
+  :type 'string
+  :group 'compile-fortran)
+
+\f
+
+;; @@ sh-mode compile variables ;;;
+(defgroup compile-sh nil
+  "Sh (Bourne Shell scripts) compilation options"
+  :group 'compilation-script)
+
+(defcustom sh-command "sh"
+  "Command to run sh scripts"
+  :type 'string
+  :group 'compile-sh)
+
+(defcustom sh-dbg-flags "-fvx"
+  "*Flags to give to sh for debugging a Bourne Shell script.
+
+The -f flag must always be present."
+  :type 'string
+  :group 'compile-sh)
+
+(defvar sh-compilation-error-regexp-alist nil
+  ;; I'd never seen a Bourne shell returning file+line where a syntax
+  ;; error occured.
+  "Alist that specifies how to match errors in sh output.
+
+See variable compilation-error-regexp-alist for more details.")
+\f
+
+;; @@ csh-mode compile variables ;;;
+(defgroup compile-csh nil
+  "Csh (C Shell) compilation options"
+  :group 'compilation-script)
+
+(defcustom csh-command "csh"
+  "Command to run csh scripts"
+  :type 'string
+  :group 'compile-csh)
+
+(defcustom csh-dbg-flags "-fVX"
+  "*Flags to give to csh for debugging a C Shell script.
+
+The -f flag must always be present."
+  :type 'string
+  :group 'compile-csh)
+
+(defvar csh-compilation-error-regexp-alist nil
+  ;; I'd never seen a C shell returning file+line where a syntax
+  ;; error occured.
+  "Alist that specifies how to match errors in csh output.
+
+See variable compilation-error-regexp-alist for more details.")
+\f
+
+;; @@ zsh-mode compile variables ;;;
+(defgroup compile-zsh nil
+  "Zsh (Z Shell scripts) compilation options"
+  :group 'compilation-script)
+
+(defcustom zsh-command "zsh"
+  "Command to run zsh scripts"
+  :type 'string
+  :group 'compile-zsh)
+
+(defcustom zsh-dbg-flags "-nCvx"
+  "*Flags to give to zsh for debugging a Z Shell script."
+  :type 'string
+  :group 'compile-zsh)
+
+(defvar zsh-compilation-error-regexp-alist nil
+  ;; I'd never seen a Z shell returning file+line where a syntax
+  ;; error occured.
+  "Alist that specifies how to match errors in csh output.
+
+See variable compilation-error-regexp-alist for more details.")
+\f
+
+;; @@ tcl-mode compile variables - JWH ;;;
+(defgroup compile-tcl nil
+  "Tcl compilation options"
+  :group 'compilation-script)
+
+(defcustom tcl-command "wish"
+  "Command to run tcl scripts"
+  :type 'string
+  :group 'compile-tcl)
+
+(defcustom tcl-dbg-flags ""
+  "*Flags to give to tcl -- none."
+  :type 'string
+  :group 'compile-tcl)
+
+(defvar tcl-compilation-error-regexp-alist
+  ;; TK  (file "/directory-path/filename.tcl" line XY)
+  '(
+    ("file \"\\([^ ]+\\)\" line \\([0-9]+\\)[)]" 1 2)
+    )
+  "Alist that specifies how to match errors in tcl output.
+
+See variable compilation-error-regexp-alist for more details.")
+\f
+
+;; @@ python-mode compile variables - BM ;;;
+(defgroup compile-python nil
+  "Python compilation options"
+  :group 'compilation-script)
+
+(defcustom python-command "python"
+  "Command to run python scripts"
+  :type 'string
+  :group 'compile-python)
+
+(defcustom python-dbg-flags ""
+  "*Flags to give to python -- none."
+  :type 'string
+  :group 'compile-phthon)
+
+(defvar python-compilation-error-regexp-alist
+  ;; TK  (file "/directory-path/filename.tcl" line XY in ZZZ)
+  '(
+    ("File \"\\([^ ]+\\)\", line \\([0-9]+\\).*" 1 2)
+    )
+  "Alist that specifies how to match errors in python output.
+
+See variable compilation-error-regexp-alist for more details.")
+\f
+
+;; @@ perl-mode compile variables ;;;
+(defgroup compile-perl nil
+  "Perl compilation options"
+  :group 'compilation-script)
+
+(defcustom perl-command "perl"
+  "Command to run perl."
+  :type 'string
+  :group 'compile-perl)
+
+(defcustom perl-dbg-flags "-w"
+  "*Flags to give to perl for debugging a Perl script."
+  :type 'string
+  :group 'compile-perl)
+
+(defvar perl-compilation-error-regexp-alist
+  ;; Contributed by Martin Jost
+  '(
+    ;; PERL 4
+    ("in file \\([^ ]+\\) at line \\([0-9]+\\).*" 1 2)
+    ;; PERL 5   Blubber at FILE line XY, <XY> line ab.
+    ("at \\([^ ]+\\) line \\([0-9]+\\)," 1 2)
+    ;; PERL 5   Blubber at FILE line XY.
+    ("at \\([^ ]+\\) line \\([0-9]+\\)." 1 2)
+    )
+  ;; This look like a paranoiac regexp: could anybody find a better one? (which WORK).
+  ;;'(("^[^\n]* \\(file\\|at\\) \\([^ \t\n]+\\) [^\n]*line \\([0-9]+\\)[\\.,]" 2 3))
+  "Alist that specifies how to match errors in perl output.
+
+See variable compilation-error-regexp-alist for more details.")
+\f
+
+;; @@ emacs lisp compile variables ;;;
+
+;;;###autoload
+(defcustom emacs-lisp-byte-compile-dir-interactive-p t
+  "*Non-nil means when byte-compiling a directory ask for each file
+needing to be recompiled or not."
+  :type 'boolean
+  :group 'compilation-elisp)
+(define-obsolete-variable-alias
+  'mode-compile-byte-compile-dir-interactive-p
+  'emacs-lisp-byte-compile-dir-interactive-p)
+
+(defcustom emacs-lisp-sources-regexp
+  (cond
+   ((boundp 'emacs-lisp-file-regexp)
+    emacs-lisp-file-regexp)
+   (t
+    "\\.el$"))
+  "Regexp to find emacs lisp sources files."
+  :type 'regexp
+  :group 'compilation-elisp)
+
+(defcustom emacs-lisp-bytecomp-ext "c"
+  "Extension added to byte-compiled emacs sources files."
+  :type 'string
+  :group 'compilation-elisp)
+\f
+
+;; @@ Misc declarations ;;;
+
+;;;###autoload
+(defconst mode-compile-version "2.28"
+  "Current version of mode-compile package.
+
+mode-compile.el,v 2.28 2003/04/01 13:52:47 boubaker Exp
+Please send bugs-fixes/contributions/comments to boubaker@cena.fr")
+
+(defconst mode-compile-help-address "heddy.Boubaker@cena.fr"
+  "E-Mail address of mode-compile maintainer.")
+\f
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; @ No user modifiable stuff below this line ;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Save old compile function. In case someone will bound
+;; mode-compile on 'compile.
+(or (fboundp 'mc--compile-sav)
+    (if (fboundp 'compile)
+        (progn
+          (fset 'mc--compile-sav (symbol-function 'compile))
+          (put 'compile 'compile-saved-on-mc--compile-sav t))
+      (error "`compile' function not known to be defined...")))
+
+;; @@ Internals variables and constants ;;;
+
+;; Mode specific
+(defvar mc--comp-lst          nil) ; c-mode,c++-mode,ada-mode,fortran-mode
+(defvar mc--def-comp          nil) ; itou
+(defvar mc--compfile-regexp   nil) ; itou
+(defvar mc--comp-varenv       nil) ; itou
+(defvar mc--comp-options      nil) ; itou
+(defvar mc--cflags-varenv     nil) ; itou
+(defvar mc--source-ext-lst    nil) ; itou
+(defvar mc--head-ext-lst      nil) ; itou
+(defvar mc--source-ext-regexp nil) ; itou
+(defvar mc--build-op-args     nil) ; itou
+(defvar mc--outfile-ext       nil) ; itou
+
+;; remote stuff
+(defvar mc--efs-path-list       nil)
+(defvar mc--remote-host         nil)
+(defvar mc--remote-host-history nil)
+(defvar mc--remote-username     nil)
+(defvar mc--remote-command      nil)
+(defvar mc--remote-pathname     nil)
+
+;; Frames/Windows stuff
+(defvar mc--other-frame nil)
+(defvar mc--ws (or
+                (and (fboundp 'console-type) (console-type))
+                (and (fboundp 'device-type)  (device-type))
+                window-system))
+
+(defvar mc--compile-command nil)
+;; Compile command used when no makefile has been found.
+;; This variable is buffer local to keep history for read-string.
+;; Unfortunately not a real history, keep only memory of
+;; the last compile command used.
+(make-variable-buffer-local 'mc--compile-command)
+
+(defvar mc--kill-compile nil)
+;; kill-compile command bound dynamically by `guess-compile'.
+(make-variable-buffer-local 'mc--kill-compile)
+
+(defvar mc--selected-makefile nil)
+(defvar mc--selected-makefile-history nil)
+;; User selected makefile among the list, to run make with.
+;; This variable is buffer local to keep history for completing-read
+;; Unfortunately not a real history, keep only memory of
+;; the last makefile used.
+(make-variable-buffer-local 'mc--selected-makefile)
+
+(defvar mc--selected-makerule nil)
+(defvar mc--selected-makerule-history nil)
+;; User selected make rule to rebuild.
+;; This variable is buffer local to keep history for completing-read
+;; Unfortunately not a real history, keep only memory of
+;; the last makerule used.
+(make-variable-buffer-local 'mc--selected-makerule)
+
+(defconst mc--find-C-main-regexp
+  "^[ \t]*\\(int\\|void\\)?[ \t\n]*main[ \t\n]*\(+" )
+;; Regexp to find the main() function in a C/C++ file
+
+(defconst mc--makefile-rules-regexp
+  "^\n*\\([^.$ \t#\n][^$ \t#\n:]*\\)[ \t]*:")
+;; Regexp to extract makefiles rules.
+;; But only those not containing references to $(VARIABLES)
+;; and not starting with `.'
+
+(defvar mc--makefile-rules nil)
+;; List of all rules extracted from makefile
+(make-variable-buffer-local 'mc--makefile-rules)
+
+(defvar mc--mkfl-buffer-tick nil)
+;; Tick counter for the buffer at the time of the rules extraction.
+(make-variable-buffer-local 'mc--mkfl-buffer-tick)
+
+(defvar mc--shell-args nil)
+;; Shell arguments for the script to debug.
+;; This variable is buffer local to keep history for read-string.
+;; Unfortunately not a real history, keep only memory of
+;; the last shell arguments used.
+(make-variable-buffer-local 'mc--shell-args)
+
+;; nil in GNU FSF Emacs, >= 0 in GNU Lucid Emacs/XEmacs
+(defconst mc--lucid-emacs-p (or (string-match "Lucid"  emacs-version)
+                                (string-match "XEmacs" emacs-version)))
+
+;; @@ Internals functions and macros ;;;
+
+(if (not (fboundp 'defsubst))
+    ;; Emacs 18
+    (fset 'defsubst (symbol-function 'defun)))
+
+(defun mc--compile (compile-command)
+  ;; Call compile with the compile command
+  ;; but append the remote-command before
+  (if (null mc--remote-command)
+      ;; local compile
+      (mc--compile-sav compile-command)
+    ;; remote compile
+    (let ((thisdir (expand-file-name (or default-directory "~"))))
+      (mc--compile-sav
+       (concat
+        ;; The command to lauch remote commands
+        mc--remote-command
+        ;; Change to this buffer directory ...
+        "'( cd " thisdir " ; "
+        ;; then run the compile command
+        compile-command " )'")))))
+
+(defsubst mc--msg (msg &rest args)
+  ;; Print MSG with ARGS and wait to let time to user
+  ;; to read the message in minibuffer.
+  (cond ((not mode-compile-expert-p)
+         (apply 'message (concat "mode-compile: " msg) args)
+         (sit-for mode-compile-reading-time))))
+
+(cond
+ ;; Check availaibles frames functions
+ ((fboundp 'make-frame)
+  ;; GNU Emacs
+  (fset 'mc--make-frame         (symbol-function 'make-frame))
+  (fset 'mc--select-frame       (symbol-function 'select-frame))
+  (fset 'mc--frame-live-p       (symbol-function 'frame-live-p))
+  (fset 'mc--make-frame-visible (symbol-function 'make-frame-visible))
+  (fset 'mc--raise-frame        (symbol-function 'raise-frame)))
+ ((fboundp 'make-screen)
+  ;; XEmacs
+  (fset 'mc--make-frame         (symbol-function 'make-screen))
+  (fset 'mc--select-frame       (symbol-function 'select-screen))
+  (fset 'mc--frame-live-p       (symbol-function 'screen-live-p))
+  (fset 'mc--make-frame-visible (symbol-function 'make-screen-visible))
+  (fset 'mc--raise-frame        (symbol-function 'raise-screen)))
+ ((fboundp 'new-screen)
+  ;; Lucid Emacs/obsolete
+  (fset 'mc--make-frame         (symbol-function 'new-screen))
+  (fset 'mc--select-frame       (symbol-function 'select-screen))
+  (fset 'mc--frame-live-p       (symbol-function 'screen-live-p))
+  (fset 'mc--make-frame-visible (symbol-function 'make-screen-visible))
+  (fset 'mc--raise-frame        (symbol-function 'raise-screen))))
+
+(defsubst mc--funcall (command &rest params)
+  ;; Run command with params in another frame or not:
+  ;; only if user ask for it and if window system is X
+  ;; (maybe test window-system is set will be enought?).
+  (cond ((and (eq mc--ws 'x)
+              mode-compile-other-frame-p)
+         ;; switch to another frame
+         (mc--msg "Switching to another frame to compile...")
+         (let ((buffer   (current-buffer))
+               (win-attr (or mode-compile-frame-parameters-alist
+                             mode-compile-default-frame-parameters))
+               (frame   (cond ((fboundp 'mc--frame-live-p)
+                                (if (mc--frame-live-p mc--other-frame)
+                                    mc--other-frame
+                                  nil))
+                               (t
+                                (mc--msg "Don't know how to check frame existence.")
+                                nil))))
+           (cond ((fboundp 'mc--make-frame)
+                  (mc--select-frame (or frame
+                                         (setq mc--other-frame
+                                               (mc--make-frame win-attr))))
+                  ;; I really don't understand why the 3 following
+                  ;; are necessary (raise-frame must be enought?).
+                  (mc--make-frame-visible mc--other-frame)
+                  (mc--raise-frame        mc--other-frame)
+                  (switch-to-buffer        buffer))
+                 (t
+                  (mc--msg "Don't know how to create a new frame."))))))
+  ;; Just run the command with it's parameters
+  (apply command params))
+
+(defun mc--byte-compile-buffer()
+  (if (fboundp 'byte-compile-buffer) (byte-compile-buffer)
+    ;; No byte-compile-buffer
+    ;; Save current-buffer in a temporary file and byte-compile it.
+    (let ((tmp-file (concat (or (getenv "TMPDIR")
+                                (concat mode-compile-dir-separator-char "tmp"))
+                            mode-compile-dir-separator-char (make-temp-name "mc--"))))
+      (save-restriction
+        (widen)
+        (write-region (point-min) (point-max) tmp-file)
+        (condition-case err
+            (byte-compile-file tmp-file)
+          ;; handler
+          (error (mc--msg "Failing to byte-compile %s, #error %s"
+                          (buffer-name) err)))
+        (delete-file tmp-file)
+        (let ((elc-file (concat tmp-file emacs-lisp-bytecomp-ext)))
+          (if (file-writable-p elc-file)
+              (condition-case err
+                  (delete-file elc-file)
+                ;; handler
+                (error (mc--msg "Failing to delete %s, #error %s"
+                                elc-file err)))))
+        (message nil))))) ; to clean minibuffer
+
+(fset 'mc--member
+      (if (fboundp 'member)
+          (symbol-function 'member)
+        ;; No member function
+        (function
+         (lambda (elt list)
+           (catch 'elt-is-member
+             (while list
+               (if (equal elt (car list))
+                   (throw 'elt-is-member list))
+               (setq list (cdr list))))))))
+
+(fset 'mc--run-hooks
+      (if (fboundp 'run-hooks)
+          (symbol-function 'run-hooks)
+        ;; No run-hooks
+        (function
+         (lambda (hooklist)
+           (mapcar '(lambda (x)
+                      ;; report an error if x not a function
+                      (funcall x))
+                   hooklist)))))
+
+(defsubst mc--read-string (prompt &optional initial-contents)
+  ;; On Lucid Emacs I use compile-history as 3rd argument but
+  ;; no history is possible with GNU emacs.
+  (if mc--lucid-emacs-p
+      (read-string prompt initial-contents 'compile-history)
+    (read-string prompt initial-contents)))
+
+(defmacro mc--eval (sym &optional arg)
+  ;; Evaluate symbol
+  (` (cond
+      ((and (symbolp (, sym))
+            (fboundp (, sym)))
+       (funcall (, sym) (, arg)))
+      (t
+       (eval (, sym))))))
+
+(defmacro mc--common-completion (alist)
+  ;; Return the greatest common string for all
+  ;; possible completions in alist.
+  (` (try-completion "" (, alist))))
+
+(defun mc--byte-recompile-files (files)
+  ;; Byte recompile all FILES which are older than their
+  ;; .elc files in the current directory
+  (let ((tmp-fl files))
+    (while (car-safe tmp-fl)
+      (let* ((el-file  (car tmp-fl))
+             (elc-file (concat el-file emacs-lisp-bytecomp-ext)))
+        (mc--msg "Checking file %s ..." el-file)
+        ;; is el-file newer than elc-file (if exists)
+        (if (and (file-newer-than-file-p el-file elc-file)
+                 (or (not emacs-lisp-byte-compile-dir-interactive-p)
+                     (y-or-n-p (format "byte-recompile file %s? " el-file))))
+            (condition-case err
+                (byte-compile-file el-file)
+              ;; handler
+              (error (mc--msg "Failing to byte-compile %s, #error %s"
+                              el-file err))))
+        (setq tmp-fl (cdr-safe tmp-fl))))
+    (mc--msg "All files processed")))
+
+(defun mc--which (file)
+  ;; Find an executable FILE in exec-path
+  (if (not (stringp file))
+      (error "mc--which: nil FILE arg"))
+  (if mc--lucid-emacs-p
+      ;; Some emacses don't have locate-file some have...
+      ;; Lucid have it in standard, some others (GNU) have it
+      ;; (add-on pkg) but the syntax is not always consistent...
+;      (locate-file file exec-path nil 1)
+      (locate-file file exec-path mode-compile-exe-file-ext 1)
+    (let ((tmp-p-lst  exec-path)
+          (found      nil)
+          (file-found nil))
+      (while (and (car-safe tmp-p-lst)
+                  (not (setq found
+                             (file-executable-p
+                              (setq file-found
+                                    (concat (car tmp-p-lst)
+                                            mode-compile-dir-separator-char
+                                            file
+                                            mode-compile-exe-file-ext))))))
+        (setq tmp-p-lst (cdr-safe tmp-p-lst)))
+      (if found file-found nil))))
+
+(defun mc--find-compiler ()
+  ;; Find user's favourite mode compiler
+  (mc--msg "Searching for your favourite %s compiler ..." mode-name)
+  (let ((tmp-comp-lst mc--comp-lst)
+        (compiler     nil))
+    (or (getenv mc--comp-varenv)
+        (progn
+          (while (and tmp-comp-lst
+                      (not (setq compiler
+                                 (mc--which (car tmp-comp-lst)))))
+            (setq tmp-comp-lst (cdr tmp-comp-lst)))
+          (file-name-nondirectory (or compiler (mc--eval mc--def-comp)))))))
+
+(defun mc--find-to-compile-file (&optional fname)
+  ;; Find the name of the file to compile.
+  (let ((file-name (or fname
+                       (buffer-file-name)
+                       (error "Compilation abort: Buffer %s has no filename."
+                              (buffer-name))))
+        (assoc-file nil)
+        (found      nil)
+        (pos        0))
+    (cond
+     ((string-match mc--source-ext-regexp file-name)
+      ;; buffer is a compileable file
+      (file-name-nondirectory file-name))
+
+     ((setq pos (string-match mc--compfile-regexp file-name))
+      ;; Buffer is not a compileable file, try to find associated
+      ;; compileable file.
+      (let ((tmp-ext-lst mc--source-ext-lst))
+        (mc--msg "Looking for a compileable companion file for %s..."
+                 (file-name-nondirectory file-name))
+        (while (and tmp-ext-lst
+                    (not (setq found
+                               (file-readable-p
+                                (setq assoc-file
+                                      (concat
+                                       (substring file-name 0 pos)
+                                       "." (car tmp-ext-lst)))))))
+          (setq tmp-ext-lst (cdr tmp-ext-lst))))
+      (if found
+          ;; A compileable companion source file found
+          (file-name-nondirectory assoc-file)
+        ;; No compileable companion source file found
+        (mc--msg "Couldn't find any compileable companion file for %s ..."
+                 (file-name-nondirectory file-name))
+        nil))
+
+     (t
+      ;; Buffer has an unknown file extension
+      ;; Could I be more cool?
+      (error "Compilation abort: Don't know how to compile %s."
+             (file-name-nondirectory file-name))))))
+
+(defun mc--guess-compile-result-fname (infile)
+  ;; Try to guess if outfile will be an object file or
+  ;; an executable file by grepping for `main()' in INFILE.
+  (let ((base-fname
+         (substring infile 0
+                    (string-match mc--source-ext-regexp infile))))
+    (save-excursion
+      ;; Create a temporary buffer containing infile contents
+      (set-buffer (find-file-noselect infile))
+      (save-excursion
+        (save-restriction
+          (widen)
+          (goto-char (point-min))
+          ;; Grep into tmp buffer for main function
+          ;; THIS WILL NOT WORK FOR PROGRAMMING LANGAGES
+          ;; WHICH ARE NOT C DIALECTS:
+          ;; In non C-ish modes I hope this regexp will never be found :-(
+          (if (re-search-forward mc--find-C-main-regexp (point-max) t)
+              (concat base-fname mode-compile-exe-file-ext)
+            (concat base-fname "." mc--outfile-ext)))))))
+
+(defun mc--build-output-args (infile)
+  ;; Build output arguments for compile command by scanning INFILE.
+  (mc--msg "Looking into %s to build compile command ..." infile)
+  (let ((out-file (mc--guess-compile-result-fname infile)))
+    (concat (if (string-match
+                 (concat "\\." mc--outfile-ext "$")
+                 out-file)
+                ;; outfile will be an object file
+                " -c "
+              ;; outfile will be an executable file
+              " ")
+            infile " -o " out-file )))
+
+(defun mc--set-remote-cmd (remote-host &optional username pathname)
+  ;; Check validity of remote-host or ask one to user
+  ;; Then build the first part of the remote command
+  (if (stringp remote-host)
+      ;; Arg is the remote host name
+      (let ((host-infos (assoc remote-host
+                               mode-compile-remote-hosts-alist)))
+        (setq mc--remote-host
+              remote-host)
+        (setq mc--remote-username
+              (or username
+                  (let ((usrnam (cdr host-infos)))
+                    (if usrnam
+                        (cond
+                         ((stringp usrnam)
+                          usrnam)
+                         ((functionp usrnam)
+                          ;; usrnam is a function call it with hostname arg
+                          (funcall usrnam mc--remote-host))
+                         (t
+                          ;; What's that??
+                          (mc--msg "%s is not a valid option using user-login-name" (pp-to-string usrnam))
+                          (user-login-name)))
+                      (user-login-name)))))
+        (setq mc--remote-pathname pathname)
+        ;; Add host to the user's list
+        (or host-infos
+            (setq mode-compile-remote-hosts-alist
+                  (append (list (list remote-host))
+                          mode-compile-remote-hosts-alist)))
+        ;; Prepare the command
+        (setq mc--remote-command
+              (concat
+               ;; "rsh host -l username"
+               mode-compile-remote-execute-command           " "
+               mode-compile-remote-execute-set-host-arg      " "
+               mc--remote-host                               " "
+               mode-compile-remote-execute-set-username-arg  " "
+               mc--remote-username                           " "
+               mode-compile-remote-execute-misc-args         " "
+               mode-compile-remote-execute-set-command-arg   " "
+                )))
+    ;; Arg is: Ask to user then check
+    (let ((rhost (completing-read
+                  "Remote host to compile to: "
+                  mode-compile-remote-hosts-alist
+                  nil nil
+                  ;; Initial contents
+                  (or mc--remote-host
+                      (car-safe (car-safe mode-compile-remote-hosts-alist)))
+                  mc--remote-host-history)))
+      (or (string= rhost "")
+          (mc--set-remote-cmd rhost)))))
+
+;(defmacro mc--makefile-test-p (makefile)
+;  (` (and (, makefile)
+;          (not (string-equal     (, makefile) ""))
+;          (not (file-directory-p (, makefile)))
+;          (file-readable-p       (, makefile)))))
+(defun mc--makefile-test-p (makefile)
+  (cond
+   ((or (not makefile)
+        (string-equal makefile ""))
+    (mc--msg "Empty makefile selection")
+    nil)
+   ((file-directory-p makefile)
+    (mc--msg "Makefile selection %s is a directory !!" makefile)
+    nil)
+   ((not (file-readable-p makefile))
+    (mc--msg "Makefile %s unreadable" makefile)
+    nil)
+   (t)))
+
+
+(if (not (fboundp 'buffer-modified-tick))
+    (fset 'buffer-modified-tick
+          ;; allways indicate modified
+          (function
+           (lambda()
+             (if mc--mkfl-buffer-tick
+                 (+ mc--mkfl-buffer-tick 1)
+               1)))))
+
+(defun  mc--get-makefile-rules (makefile)
+  ;; Try to find if makefile's buffer has been modified
+  ;; since last rule extraction
+  (if (or (not mc--mkfl-buffer-tick)
+          (not (equal mc--mkfl-buffer-tick
+                      (buffer-modified-tick))))
+      (save-excursion
+        (save-restriction
+          (widen)
+          (goto-char (point-min))
+          (setq mc--mkfl-buffer-tick (buffer-modified-tick))
+          (setq mc--makefile-rules   nil)
+          (mc--msg "Extracting rules from %s ..." makefile)
+          ;; Grep into tmp buffer for makefile rules
+          (while (re-search-forward mc--makefile-rules-regexp nil t)
+            (let ((rule (buffer-substring
+                         (match-beginning 1)
+                         (match-end       1))))
+              ;; add rule to list if it don't match the ignore regexp
+              ;; and if not allready in rules list.
+              (if (and
+                   (or (not mode-compile-ignore-makerule-regexp)
+                       (not (string-match
+                             mode-compile-ignore-makerule-regexp
+                             rule)))
+                   (not (mc--member rule mc--makefile-rules)))
+                  (setq mc--makefile-rules
+                        (append mc--makefile-rules
+                                (list rule))))))))
+    (mc--msg "Rules had already been extracted from %s ..." makefile))
+  ;; Always add an empty rule to allow `default' choice.
+  (append mc--makefile-rules '([])))
+
+(defun mc--makerule-completion (alist outfile &optional pref)
+  ;; Return the makerule completion according to the prefered
+  ;; default makerule
+  (let ((preference (or pref
+                        mode-compile-prefered-default-makerule)))
+    (mc--msg "Prefered makerule choice is '%s" preference)
+    (cond
+     ((eq preference 'none)
+      ;; Just show max common completion string to user
+      (or (mc--common-completion alist) ""))
+
+     ((eq preference 'all)
+      ;; Find the all rule or 'none
+      (if (assoc "all" alist) "all"
+        (mc--makerule-completion alist outfile 'none)))
+
+     ((eq preference 'file)
+      ;; The out file is prefered or 'none
+      (or outfile (mc--makerule-completion alist outfile 'none)))
+
+     ((eq preference 'default)
+      ;; Find the default rule or ""
+      (if (assoc "default" alist) "default" ""))
+
+     (t
+      ;; Invalid preference return 'none
+      (mc--msg "Invalid `mode-compile-prefered-default-makerule': '%s"
+               mode-compile-prefered-default-makerule)
+      (mc--makerule-completion alist outfile 'none)))))
+
+(defun mc--choose-makefile-rule (makefile &optional outfile)
+  ;; Choose the makefile rule and set it makefile local
+  (save-excursion
+    ;; Switch to makefile buffer
+    (set-buffer (find-file-noselect makefile))
+    (setq mc--selected-makerule
+          ;; Add the name of the out file to the makefile
+          ;; rules list if not allready in.
+          (let* ((mk-rules-alist (mc--get-makefile-rules makefile))
+                 (choices        (mapcar '(lambda (x) (list x))
+                                         (if (or (not outfile)
+                                                 (mc--member outfile
+                                                             mk-rules-alist))
+                                             mk-rules-alist
+                                           (append mk-rules-alist
+                                                   (list outfile))))))
+            (completing-read
+             (if mode-compile-expert-p
+                 "Make rule: "
+               "Using `make', enter rule to rebuild ([TAB] to complete): ")
+             choices
+             nil nil
+             ;; initial contents
+             (or mc--selected-makerule
+                 (mc--makerule-completion choices outfile
+                                          (if outfile 'file)))
+             mc--selected-makerule-history
+             )))))
+
+(defmacro mc--cleanup-makefile-list (makefile-list)
+  ;; Remove unusable and/or backups makefiles from list
+  (` (let ((newlist))
+       (mapcar
+        '(lambda (x)
+           (if (and (mc--makefile-test-p x)
+                    (or (not mode-compile-ignore-makefile-backups)
+                        (not (string-match
+                              mode-compile-makefile-backups-regexp
+                              x))))
+               (setq newlist (cons x newlist))
+             (mc--msg "Removing makefile \"%s\" from completion list"
+                      x)))
+        (, makefile-list))
+       newlist)))
+
+(defun mc--makefile-to-use (&optional directory)
+  ;; Find the makefile to use in the current directory
+  (let ((makefile-list (mc--cleanup-makefile-list
+                        (directory-files
+                         ;; I do not use the 5th parameter in Lucid Emacs
+                         ;; to be compatible with GNU Emacs which accept
+                         ;; only 4 parameters - no NOSORT -.
+                         (or directory default-directory)
+                         nil mode-compile-makefile-regexp t))))
+    (cond
+     ((not makefile-list)
+      ;; No makefile found
+      nil)
+
+     ((and (not (cdr-safe makefile-list))
+           (mc--makefile-test-p (car makefile-list)))
+      ;; Only one valid makefile
+      (car makefile-list))
+
+     (t
+      ;; Many makefiles in directory ask user to select one
+      (let ((choices  (mapcar
+                       '(lambda (x) (list x))
+                       makefile-list))
+            (makefile nil))
+        (while
+            ;; While the makefile do not pass the test.
+            (not (mc--makefile-test-p
+                  (setq makefile
+                        (completing-read
+                         (if mode-compile-expert-p
+                             "Makefile: "
+                           "Using `make', select makefile to use ([TAB] to complete): ")
+                         choices
+                         nil t
+                         ;; initial contents
+                         (or mc--selected-makefile
+                             (mc--common-completion choices))
+                         mc--selected-makefile-history
+                         )))))
+        makefile)))))
+
+(defun mc--set-command (&optional file)
+  ;; Return a compilation command, built according to the existence
+  ;; of a makefile or not, to compile FILE .
+  (setq completion-ignore-case nil) ; let completion be case sensitive
+  (let ((to-compile-fname (or file (mc--find-to-compile-file))))
+    (if (setq mc--selected-makefile (mc--makefile-to-use))
+        (progn
+          ;; A makefile found in the directory:
+          ;; using make to compile
+          (let ((out-fname (if to-compile-fname
+                               (mc--guess-compile-result-fname
+                                to-compile-fname)
+                             nil)))
+            ;; build make command by asking rule to user
+            (concat mode-compile-make-program " "
+                    (or (mc--eval mode-compile-make-options) "")
+                    " -f " mc--selected-makefile " "
+                    (mc--choose-makefile-rule
+                     mc--selected-makefile out-fname))))
+      ;; else
+      ;; No makefile: build compile command asking  for confirmation to user.
+      ;; Should this be replaced by the creation of a makefile (and then
+      ;; running it) as rms proposed me?
+      (or mc--compile-command
+          (setq mc--compile-command
+                (concat (setq mode-compile-choosen-compiler
+                              (mc--find-compiler)) " "
+                        (or (getenv mc--cflags-varenv)
+                            (mc--eval mc--comp-options))
+                        (if to-compile-fname
+                            (if mc--build-op-args
+                               (mc--build-output-args to-compile-fname)
+                             (concat " " to-compile-fname)
+                             )
+                          " "))))
+      (if (not mode-compile-never-edit-command-p)
+          (setq mc--compile-command
+                (mc--read-string
+                 (if mode-compile-expert-p
+                     "Compile command: "
+                   (if to-compile-fname
+                       (format "Edit command to compile %s: "
+                               to-compile-fname)
+                     "Edit compile command: " ))
+                 mc--compile-command))
+        mc--compile-command))))
+
+(defun mc--shell-compile (shell dbgflags &optional errors-regexp-alist)
+  ;; Run SHELL with debug flags DBGFLAGS on current-buffer
+  (let* ((shcmd   (or (mc--which shell)
+                      (error "Compilation abort: command %s not found" shell)))
+         (shfile  (or mc--remote-pathname (buffer-file-name)
+                      (error "Compilation abort: Buffer %s has no filename"
+                             (buffer-name))))
+         (run-cmd (concat shcmd " " dbgflags " " shfile " "
+                          (setq mc--shell-args
+                                (read-string (if mode-compile-expert-p
+                                                 "Argv: "
+                                               (format "Arguments to %s %s script: "
+                                                       shfile shell))
+                                             mc--shell-args)))))
+    ;; Modify compilation-error-regexp-alist if needed
+    (if errors-regexp-alist
+        (progn
+          ;; Set compilation-error-regexp-alist from compile
+          (or (listp errors-regexp-alist)
+              (error "Compilation abort: In mc--shell-compile errors-regexp-alist not a list."))
+          ;; Add new regexp alist to compilation-error-regexp-alist
+          (mapcar '(lambda(x)
+                     (if (mc--member x compilation-error-regexp-alist) nil
+                       (setq compilation-error-regexp-alist
+                             (append (list x)
+                                     compilation-error-regexp-alist))))
+                  errors-regexp-alist)))
+    ;; Run compile with run-cmd
+    (mc--compile run-cmd)))
+
+(defmacro mc--assq-get-fcomp (asq)
+  ;; Return compile-function associated to ASQ
+  (` (let* ((mode  (cdr  (, asq)))
+            (massq (assq mode mode-compile-modes-alist)))
+       (if massq (car-safe (cdr massq))))))
+
+(defmacro mc--assq-get-fkill (asq)
+  ;; Return kill-compile-function associated to ASQ
+  (` (let* ((mode  (cdr  (, asq)))
+            (massq (assq mode mode-compile-modes-alist)))
+       (if massq (car-safe (cdr-safe (cdr massq)))))))
+
+(defun mc--lookin-for-shell ()
+  ;; Look into current-buffer to see if it is a shell script
+  ;; and return function to compile it or nil.
+  (mc--msg "Looking if buffer %s is a shell script..." (buffer-name))
+  (save-excursion
+    (save-restriction
+      (widen)
+      (goto-char (point-min))
+      (if (looking-at "#![ \t]*/\\([^ \t\n]+/\\)\\([^ \t\n]+\\)")
+          (let* ((shell-name (buffer-substring (match-beginning 2)
+                                               (match-end       2)))
+                 (shell-assq (assoc shell-name mode-compile-shell-alist)))
+            (if shell-assq
+                (progn
+                  (mc--msg "Buffer is a %s script" shell-name)
+                  (setq mc--kill-compile (mc--assq-get-fkill shell-assq))
+                  (mc--assq-get-fcomp shell-assq))
+              nil))))))
+
+(defun mc--lookat-name ()
+  ;; Lookat buffer file name to see if it can return a function
+  ;; to compile it or nil.
+  (mc--msg "Trying to guess compile command from buffer %s file name..."
+           (buffer-name))
+  (let ((fname (buffer-file-name)))
+    (if (not fname) nil
+      ;; try regexp from mode-compile-filename-regexp-alist
+      (let ((tmp-al mode-compile-filename-regexp-alist)
+            (found  nil))
+        (while (and tmp-al (car tmp-al) (not found))
+          ;; evaluate to string
+          (let ((regxp (mc--eval (car (car tmp-al)))))
+            (if (string-match regxp fname)
+                (setq found (car tmp-al)))
+            (setq tmp-al (cdr tmp-al))))
+        (if (not found)
+            nil
+          (mc--msg "File %s matches regexp %s" fname (car found))
+          (setq mc--kill-compile (mc--assq-get-fkill found))
+          (mc--assq-get-fcomp found))))))
+\f
+
+;; @ mode specific functions ;;;
+
+(defun cc-compile ()
+  "Run `compile' with a dynamically built command for `c-mode'.
+
+The command is built depending of the existence of a makefile (which could
+be specified by changing value of variable mode-compile-makefile-regexp) in
+the current directory or not.
+If no makefile is found try to run a C compiler on the file or it's companion.
+
+See also variables:
+ -- cc-compilers-list
+ -- cc-default-compiler
+ -- cc-companion-file-regexp
+ -- cc-compiler-varenv
+ -- cc-cflags-varenv
+ -- cc-source-ext-list
+ -- cc-headers-ext-list
+ -- cc-source-file-ext-regexp"
+  (setq
+   mc--comp-lst          cc-compilers-list
+   mc--def-comp          cc-default-compiler
+   mc--compfile-regexp   cc-companion-file-regexp
+   mc--comp-varenv       cc-compiler-varenv
+   mc--comp-options      cc-default-compiler-options
+   mc--cflags-varenv     cc-cflags-varenv
+   mc--source-ext-lst    cc-source-ext-list
+   mc--head-ext-lst      cc-headers-ext-list
+   mc--source-ext-regexp cc-source-file-ext-regexp
+   mc--build-op-args     cc-build-output-args
+   mc--outfile-ext       cc-object-file-ext
+   )
+  (mc--compile (mc--set-command)))
+
+(defun java-compile ()
+  "Run `compile' with a dynamically built command for `java-mode'.
+
+The command is built depending of the existence of a makefile (which could
+be specified by changing value of variable mode-compile-makefile-regexp) in
+the current directory or not.
+If no makefile is found try to run a Java compiler on the file or it's
+companion.
+
+See also variables:
+ -- java-compilers-list
+ -- java-default-compiler
+ -- java-companion-file-regexp
+ -- java-compiler-varenv
+ -- java-cflags-varenv
+ -- java-source-ext-list
+ -- java-headers-ext-list
+ -- java-source-file-ext-regexp"
+  (setq
+   mc--comp-lst          java-compilers-list
+   mc--def-comp          java-default-compiler
+   mc--compfile-regexp   java-companion-file-regexp
+   mc--comp-varenv       java-compiler-varenv
+   mc--comp-options      java-default-compiler-options
+   mc--cflags-varenv     java-cflags-varenv
+   mc--source-ext-lst    java-source-ext-list
+   mc--head-ext-lst      java-headers-ext-list
+   mc--source-ext-regexp java-source-file-ext-regexp
+   mc--build-op-args     java-build-output-args
+   mc--outfile-ext       java-object-file-ext
+   )
+  (mc--compile (mc--set-command)))
+
+(defun c++-compile ()
+  "Run `compile' with a dynamically built command for `c++-mode'.
+
+The command is built depending of the existence of a makefile (which could
+be specified by changing value of variable mode-compile-makefile-regexp) in
+the current directory or not.
+If no makefile is found try to run a C++ compiler on the file or it's companion.
+
+See also variables:
+ -- c++-compilers-list
+ -- c++-default-compiler
+ -- c++-companion-file-regexp
+ -- c++-compiler-varenv
+ -- c++-cflags-varenv
+ -- c++-source-ext-list
+ -- c++-headers-ext-list
+ -- c++-source-file-ext-regexp"
+  (setq
+   mc--comp-lst          c++-compilers-list
+   mc--def-comp          c++-default-compiler
+   mc--compfile-regexp   c++-companion-file-regexp
+   mc--comp-varenv       c++-compiler-varenv
+   mc--comp-options      c++-default-compiler-options
+   mc--cflags-varenv     c++-cflags-varenv
+   mc--source-ext-lst    c++-source-ext-list
+   mc--head-ext-lst      c++-headers-ext-list
+   mc--source-ext-regexp c++-source-file-ext-regexp
+   mc--build-op-args     c++-build-output-args
+   mc--outfile-ext       c++-object-file-ext
+   )
+  (mc--compile (mc--set-command)))
+
+
+(defun ada-compile ()
+  "Run `compile' with a dynamically built command for `ada-mode'.
+
+The command is built depending of the existence of a makefile (which could
+be specified by changing value of variable mode-compile-makefile-regexp) in
+the current directory or not.
+If no makefile is found try to run an Ada compiler on the file.
+
+See also variables:
+ -- ada-compilers-list
+ -- ada-default-compiler
+ -- ada-companion-file-regexp
+ -- ada-compiler-varenv
+ -- ada-aflags-varenv
+ -- ada-source-ext-list
+ -- ada-headers-ext-list
+ -- ada-source-file-ext-regexp)"
+  (setq
+   mc--comp-lst          ada-compilers-list
+   mc--def-comp          ada-default-compiler
+   mc--compfile-regexp   ada-companion-file-regexp
+   mc--comp-varenv       ada-compiler-varenv
+   mc--comp-options      ada-default-compiler-options
+   mc--cflags-varenv     ada-aflags-varenv
+   mc--source-ext-lst    ada-source-ext-list
+   mc--head-ext-lst      ada-headers-ext-list
+   mc--source-ext-regexp ada-source-file-ext-regexp
+   mc--build-op-args     ada-build-output-args
+   mc--outfile-ext       ada-object-file-ext
+   )
+  (mc--compile (mc--set-command)))
+
+
+(defun f77-compile ()
+  "Run `compile' with a dynamically built command for `fortran-mode'.
+
+The command is built depending of the existence of a makefile (which could
+be specified by changing value of variable mode-compile-makefile-regexp) in
+the current directory or not.
+If no makefile is found try to run a Fortran compiler on the file or it's companion..
+
+See also variables:
+ -- f77-compilers-list
+ -- f77-default-compiler
+ -- f77-companion-file-regexp
+ -- f77-compiler-varenv
+ -- f77-cflags-varenv
+ -- f77-source-ext-list
+ -- f77-headers-ext-list
+ -- f77-source-file-ext-regexp)"
+  (setq
+   mc--comp-lst          f77-compilers-list
+   mc--def-comp          f77-default-compiler
+   mc--compfile-regexp   f77-companion-file-regexp
+   mc--comp-varenv       f77-compiler-varenv
+   mc--cflags-varenv     f77-cflags-varenv
+   mc--comp-options      f77-default-compiler-options
+   mc--source-ext-lst    f77-source-ext-list
+   mc--head-ext-lst      f77-headers-ext-list
+   mc--source-ext-regexp f77-source-file-ext-regexp
+   mc--build-op-args     f77-build-output-args
+   mc--outfile-ext       f77-object-file-ext
+   )
+  (mc--compile (mc--set-command)))
+
+
+(defun elisp-compile ()
+  "Run `byte-compile' on the current Emacs lisp buffer.
+For `emacs-lisp-mode' and `lisp-interaction-mode'.
+
+Produce a `.elc' file if possible or `byte-compile' only the buffer."
+  (let ((comp-file (or (buffer-file-name) "")))
+    (if (string-match emacs-lisp-sources-regexp comp-file)
+        (progn
+          (mc--msg "Byte compiling file %s ..." comp-file)
+          (byte-compile-file comp-file))
+      (mc--msg "Byte compiling buffer %s #No .elc produced ..." (buffer-name))
+      (mc--byte-compile-buffer))))
+
+
+(defun makefile-compile (&optional makefile)
+  "Run `make' on the current-buffer (`makefile-mode').
+
+The user is prompted for a selection of make rules to build."
+  (let ((mkfile (or makefile (buffer-file-name)
+                    (error
+                     "Compilation abort: buffer %s has no file name"
+                     (buffer-name)))))
+    (setq mc--selected-makefile mkfile)
+    (setq mc--compile-command
+          (concat mode-compile-make-program " "
+                  (or (mc--eval mode-compile-make-options) "")
+                  " -f " mkfile " "
+                  (mc--choose-makefile-rule mkfile))))
+    (mc--compile mc--compile-command))
+
+
+(defun dired-compile ()
+  "Run `make' if a Makefile is present in current directory (`dired-mode').
+
+The user is prompted for a selection of a makefile to choose if many
+matching `mode-compile-makefile-regexp' are present in the directory and
+for the make rules to build. If directory contain no makefile the function
+try to find if there are some un-byte-compiled .el files and recompile them
+if needed.
+Ask for the complete `compile-command' if no makefile and no .el files found."
+  (let ((makefile (mc--makefile-to-use)))
+    (if makefile
+        ;; Makefile exists compile with it
+        (makefile-compile makefile)
+      ;; No makefile found look for some .el files
+      (mc--msg "No makefile found, looking for .el files ...")
+      (let ((el-files (directory-files
+                       default-directory nil emacs-lisp-sources-regexp)))
+        (if el-files
+            ;; Some .el files found byte-recompile them
+            (mc--byte-recompile-files el-files)
+          ;; No .el files ask compile command to user
+          (mc--msg "No .el files found in directory %s" default-directory)
+          (default-compile))))))
+
+
+(defun sh-compile ()
+  "Run `sh-command' (Bourne Shell) with `sh-dbg-flags' on current-buffer (`sh-mode').
+
+User is prompted for arguments to run his sh program with.
+If you want to step throught errors set the variable `sh-compilation-error-regexp-alist'
+to a value understandable by compile's `next-error'.
+See variables compilation-error-regexp-alist or sh-compilation-error-regexp-alist."
+  (mc--shell-compile sh-command sh-dbg-flags sh-compilation-error-regexp-alist))
+
+
+(defun csh-compile ()
+  "Run `csh-command' (C Shell) with `csh-dbg-flags' on current-buffer (`csh-mode').
+
+User is prompted for arguments to run his csh program with.
+If you want to step throught errors set the variable `csh-compilation-error-regexp-alist'
+to a value understandable by compile's `next-error'.
+See variables compilation-error-regexp-alist or csh-compilation-error-regexp-alist."
+  (mc--shell-compile csh-command csh-dbg-flags csh-compilation-error-regexp-alist))
+
+
+(defun zsh-compile ()
+  "Run `zsh-command' (Z Shell) with `zsh-dbg-flags' on current-buffer (`zsh-mode').
+
+User is prompted for arguments to run his zsh program with.
+If you want to step throught errors set the variable `zsh-compilation-error-regexp-alist'
+to a value understandable by compile's `next-error'.
+See variables compilation-error-regexp-alist or zsh-compilation-error-regexp-alist."
+  (mc--shell-compile zsh-command zsh-dbg-flags zsh-compilation-error-regexp-alist))
+
+
+(defun perl-compile ()
+  "Run Perl with `perl-dbg-flags' on current-buffer (`perl-mode').
+
+User is prompted for arguments to run his perl program with.
+If you want to step throught errors set the variable `perl-compilation-error-regexp-alist'
+to a value understandable by compile's `next-error'.
+See variables compilation-error-regexp-alist or perl-compilation-error-regexp-alist."
+  (mc--shell-compile perl-command perl-dbg-flags perl-compilation-error-regexp-alist))
+
+
+(defun tcl-compile ()
+  ;; JWH
+  "Run `tcl-command' with `tcl-dbg-flags' on current-buffer (`tcl-mode').
+
+User is prompted for arguments to run his Tcl/Tk program with.
+If you want to step throught errors set the variable `tcl-compilation-error-regexp-alist'
+to a value understandable by compile's `next-error'.
+See variables compilation-error-regexp-alist or tcl-compilation-error-regexp-alist."
+  (mc--shell-compile tcl-command tcl-dbg-flags tcl-compilation-error-regexp-alist))
+
+
+(defun python-compile ()
+  ;; BM
+  "Run `python-command' with `python-dbg-flags' on current-buffer (`python-mode').
+
+User is prompted for arguments to run his Python program with.
+If you want to step throught errors set the variable `python-compilation-error-regexp-alist'
+to a value understandable by compile's `next-error'.
+See variables compilation-error-regexp-alist or python-compilation-error-regexp-alist."
+  (mc--shell-compile python-command python-dbg-flags python-compilation-error-regexp-alist))
+
+
+(defun default-compile ()
+  "Default function invoked by `mode-compile' (\\[mode-compile])
+when everything else failed.
+
+Ask to user to edit `compile-command' and run `compile' (\\[compile]) with it."
+  (setq mc--compile-command
+        (mc--read-string
+         (if mode-compile-expert-p
+             "Compile command: "
+           (format "Edit command to compile %s : " (buffer-name)))
+         (or mc--compile-command compile-command)))
+  (mc--compile mc--compile-command))
+
+(defvar mc--makefile) ;; Just to avoid compiler warning
+(defun guess-compile ()
+  "Try to guess how to compile current-buffer.
+
+When the compile command could not be extrapolated from major-mode this function
+is called which try to guess from number of parameters which command to build.
+The steps to guess which command to use to compile are:
+  1st : Look into the file to check if it is a shell script
+        See variable mode-compile-shell-alist
+  2nd : Try to guess from the file name
+        See variable mode-compile-filename-regexp-alist
+  3rd : Look for a makefile in the current directory
+        See variable mode-compile-makefile-regexp
+  Last: Give up and ask user for the command to use
+        See function default-compile"
+  (mc--msg "Trying to guess how to compile buffer %s ..." (buffer-name))
+  (let ((mc--makefile))
+    (funcall
+     (or
+      ;; step 1
+      (mc--lookin-for-shell)
+      ;; step 2
+      (mc--lookat-name)
+      ;; step 3
+      (progn
+        (mc--msg "Looking for a makefile in current directory...")
+        (if (setq mc--makefile (mc--makefile-to-use
+                                (and (buffer-file-name)
+                                     (file-name-directory (buffer-file-name)))))
+            (progn
+              (setq mc--kill-compile 'kill-compilation)
+              ;; Byte-compiling says `makefile' is not referenced.
+              '(lambda () (makefile-compile mc--makefile)))))
+      ;; step 4
+      (progn
+        (mc--msg "Don't know how to compile %s, giving up..."
+                 (buffer-name))
+        (setq mc--kill-compile 'kill-compilation)
+        'default-compile)))))
+\f
+
+;; @ user accessible/exported function ;;;
+
+;; get reporter-submit-bug-report when byte-compiling
+(and (fboundp 'eval-when-compile)
+     (eval-when-compile (require 'reporter)))
+
+;;;###autoload
+(defun mode-compile-submit-bug-report ()
+  "*Submit via mail a bug report on mode-compile v2.27."
+  (interactive)
+  (and
+   (y-or-n-p "Do you REALLY want to submit a report on mode-compile? ")
+   (require 'reporter)
+   (reporter-submit-bug-report
+    mode-compile-help-address
+    (concat "mode-compile " mode-compile-version)
+    (list
+     ;; Interesting mode-compile variables
+     'mode-compile-modes-alist
+     'mode-compile-filename-regexp-alist
+     'mode-compile-shell-alist
+     'mode-compile-makefile-regexp
+     'mode-compile-make-program
+     'mode-compile-default-make-options
+     'mode-compile-make-options
+     'mode-compile-reading-time
+     'mode-compile-expert-p
+     'mode-compile-never-edit-command-p
+     'mode-compile-save-all-p
+     'mode-compile-always-save-buffer-p
+     'mode-compile-before-compile-hook
+     'mode-compile-after-compile-hook
+     'mode-compile-before-kill-hook
+     'mode-compile-after-kill-hook
+     'mode-compile-other-frame-p
+     'mode-compile-other-frame-name
+     'mode-compile-frame-parameters-alist
+     'mode-compile-prefered-default-makerule
+     'emacs-lisp-byte-compile-dir-interactive-p
+     ;; others variables
+     'features
+     'compilation-error-regexp-alist
+     'compile-command
+     )
+    nil
+    nil
+    "Dear Heddy,")))
+\f
+
+;;;###autoload
+(defun mode-compile (&optional remote-host)
+  "*Compile the file in the current buffer with a dynamically built command.
+
+The command is built according to the current major mode the function
+was invoked from.
+
+Running this command preceded by universal-argument (\\[universal-argument])
+allows remote compilation, the user is prompted for a host name to run the
+compilation command on.
+
+Currently know how to compile in:
+ `c-mode' ,              -- function cc-compile.
+ `java-mode' ,           -- function java-compile.
+ `c++-mode',             -- function c++-compile.
+ `ada-mode',             -- function ada-compile.
+ `fortran-mode',         -- function f77-compile.
+ `emacs-lisp-mode'       -- function elisp-compile.
+ `lisp-interaction-mode' -- function elisp-compile.
+ `makefile-mode'         -- function makefile-compile.
+ `dired-mode'            -- function dired-compile.
+ `sh-mode'               -- function sh-compile.
+ `csh-mode'              -- function csh-compile.
+ `zsh-mode'              -- function zsh-compile.
+ `perl-mode'             -- function perl-compile.
+ `cperl-mode'            -- function perl-compile.
+ `tcl-mode'              -- function tcl-compile.
+ `python-mode'           -- function python-compile.
+ `fundamental-mode'      -- function guess-compile.
+ `text-mode'             -- function guess-compile.
+ `indented-text-mode'    -- function guess-compile.
+ `compilation-mode'      -- function default-compile.
+ The function `guess-compile' is called when mode is unknown.
+
+The variable `mode-compile-modes-alist' contain description of known
+modes.  The hooks variables `mode-compile-before-compile-hook' and
+`mode-compile-after-compile-hook' are run just before and after
+invoking the compile command of the mode.
+
+Use the command `mode-compile-kill' (\\[mode-compile-kill]) to abort a
+running compilation.
+
+Bound on \\[mode-compile]."
+  (interactive "P")
+  ;; reinit
+  (setq
+   mc--efs-path-list  nil
+   mc--remote-command nil)
+  (if remote-host
+      ;; Remote compilation asked
+      ;; prepare remote command
+      (mc--set-remote-cmd remote-host)
+    ;; Not asked but check buffer-file-name to see
+    ;; if it is not an efs file
+    (setq mc--efs-path-list (and (fboundp 'efs-ftp-path)
+                                 (buffer-file-name)
+                                 (efs-ftp-path (buffer-file-name))))
+    (and mc--efs-path-list (mc--set-remote-cmd
+                            (car mc--efs-path-list)
+                            (nth 1 mc--efs-path-list)
+                            (nth 2 mc--efs-path-list))))
+  (if (and mode-compile-always-save-buffer-p
+           (buffer-file-name))
+      ;; save-buffer allready check if buffer had been modified
+      (save-buffer))
+  (if mode-compile-save-all-p (save-some-buffers t))
+  ;; Check if compile-command set as local variable
+  (if (and
+       (boundp 'compile-command)
+       (local-variable-p 'compile-command (current-buffer))
+       compile-command ; not null
+       (if mc--compile-command
+           (equal compile-command mc--compile-command)
+         t)
+       )
+      ;; Just ask user and go
+      (progn
+        (mc--run-hooks 'mode-compile-before-compile-hook)
+        (default-compile)
+        (mc--run-hooks 'mode-compile-after-compile-hook)
+        )
+    ;; Here is the real work
+    (let ((mode-elem (assq major-mode mode-compile-modes-alist)))
+      (if mode-elem
+          ;; known mode
+          (progn
+            (mc--msg (substitute-command-keys
+                      "Compiling in %s mode ... \\[mode-compile-kill] to kill.")
+                     mode-name)
+            (mc--run-hooks 'mode-compile-before-compile-hook)
+            ;; mc--funcall can launch the compilation
+            ;; in another frame.
+            (mc--funcall   (car (cdr mode-elem)))
+            (mc--run-hooks 'mode-compile-after-compile-hook))
+        ;; unknown mode: try to guess
+        (mc--msg (substitute-command-keys
+                  "Don't know how to compile in %s mode, guessing... \\[mode-compile-kill] to kill.")
+                 mode-name)
+        (mc--run-hooks 'mode-compile-before-compile-hook)
+        ;; mc--funcall can launch the compilation
+        ;; in another frame.
+        (mc--funcall   'guess-compile)
+        (mc--run-hooks 'mode-compile-after-compile-hook)))))
+
+(provide 'mode-compile)
+\f
+
+;;;###autoload
+(defun mode-compile-kill()
+  "*Kill the running compilation launched by `mode-compile' (\\[mode-compile]) \
+command.
+
+The compilation command is killed according to the current major mode
+the function was invoked from.
+
+Currently know how to kill compilations from:
+ `c-mode' ,              -- function kill-compilation.
+ `java-mode' ,           -- function kill-compilation.
+ `c++-mode' ,            -- function kill-compilation.
+ `ada-mode' ,            -- function kill-compilation.
+ `fortran-mode' ,        -- function kill-compilation.
+ `emacs-lisp-mode'       -- function keyboard-quit.
+ `lisp-interaction-mode' -- function keyboard-quit.
+ `makefile-mode'         -- function kill-compilation.
+ `dired-mode'            -- function kill-compilation.
+ `sh-mode'               -- function kill-compilation.
+ `csh-mode'              -- function kill-compilation.
+ `zsh-mode'              -- function kill-compilation.
+ `perl-mode'             -- function kill-compilation.
+ `cperl-mode'            -- function kill-compilation.
+ `tcl-mode'              -- function kill-compilation.
+ `python-mode'           -- function kill-compilation.
+ `fundamental-mode'      -- Bound dynamically.
+ `text-mode'             -- Bound dynamically.
+ `indented-text-mode'    -- Bound dynamically.
+ `compilation-mode'      -- function kill-compilation.
+
+The variable `mode-compile-modes-alist' contain description of ALL
+known modes.  The hooks variables `mode-compile-before-kill-hook' and
+`mode-compile-after-kill-hook' are run just before and after invoking
+the kill compile command of the mode.
+
+Bound on \\[mode-compile-kill]."
+  (interactive)
+  (let ((mode-elem (assq major-mode mode-compile-modes-alist)))
+    (if mode-elem
+        ;; known mode
+        (progn
+          (mc--run-hooks 'mode-compile-before-kill-hook)
+          (mc--msg "Killing compilation in %s mode..." mode-name)
+          (let ((killfun (or (car-safe (cdr (cdr mode-elem)))
+                             mc--kill-compile
+                             nil)))
+            (if killfun
+                ;; I don't call mc--funcall here caus' we don't need
+                ;; to switch to another frame to kill a compilation.
+                (funcall killfun)
+              (mc--msg "Unable to kill compilation in %s mode..." mode-name))
+            (mc--run-hooks 'mode-compile-after-kill-hook)))
+      ;; unknown mode
+      (mc--msg "Don't know how to kill compilation in %s mode"
+               mode-name))))
+
+(provide 'mode-compile-kill)
+
+\f
+
+;;; Local variables:
+;;; outline-regexp: ";; @+"
+;;; eval: (outline-minor-mode 1)
+;;; End:
+
+;;; mode-compile.el ends here
diff --git a/emacs_el/mutt.el b/emacs_el/mutt.el
new file mode 100644 (file)
index 0000000..2f3a39e
--- /dev/null
@@ -0,0 +1,396 @@
+;; mutt.el --- Use Emacs 20 as an external editor for the Mutt mailer
+;; Copyright 1998 Eric Kidd
+
+;; Author: Eric Kidd <eric.kidd@pobox.com>
+;; Version: $Revision: 1.4 $
+
+;; This is free software distributed under the GPL, yadda, yadda, yadda.
+;; It has no warranty. See the GNU General Public License for more
+;; information. Send me your feature requests and patches, and I'll try
+;; to integrate everything.
+
+;;; Commentary:
+
+;; This is a major mode for use with Mutt, the spiffy *nix mailreader
+;; du jour. See <http://www.cs.hmc.edu/~me/mutt/index.html>. To use this
+;; mode, add the following line to the .emacs file in your home directory:
+;;
+;;   (load "/your/local/path/to/this/file/mutt")
+;;
+;; Note that you can omit to ".el" from the file name when calling load.
+;;
+;; If you want to make it available to all your users, type \C-h v
+;; load-path RET, pick an appropriate directory for mutt.el, and modify
+;; your sitewide default.el to (require 'mutt).
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Thanks
+;;;
+;;; Dave Pearson: Code, feature ideas, Mutt experience. Many thanks!
+;;; Louis Theran: Encouragement to make Mutt mode work like Emacs MUAs.
+;;; Ronald: Enlightening gripes about what Emacs should do, but doesn't.
+;;; Robert Napier: Bug reports about font-lock mode, fancy wrapping.
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Revision History
+;;;
+;;; $Log: mutt.el,v $
+;;; Revision 1.4  1998/04/11 00:05:46  emk
+;;; Fixed font-lock bug. Also made mutt-mode a little more careful about
+;;; saving various bits of Emacs state when moving around the buffer.
+;;;
+;;; Revision 1.3  1998/03/25 00:37:36  emk
+;;; Added support for menus and font-lock mode, plus a few bug fixes.
+;;;
+;;; Revision 1.2  1998/03/24 13:19:46  emk
+;;; Major overhaul--more commands, a minor mode for header editing, and other
+;;; desirable features. Attaching files seems to be broken, though.
+;;;
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Required Packages
+
+(require 'derived)
+(require 'cl) ; Big but featureful. Do we need this?
+(require 'easymenu)
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Customization Support
+;;;
+;;; Set up our customizable features. You can edit these (and lots of other
+;;; fun stuff) by typing M-x customize RET. The Mutt preferences can be
+;;; found under the [Applications] [Mail] category.
+
+(defgroup mutt nil
+  "Composing e-mail messages with Mutt.
+Emacs can run as an external editor for Mutt, the spiffy Unix mail reader
+du jour. You can get Mutt from <http://www.cs.hmc.edu/~me/mutt/index.html>."
+  :group 'mail)
+
+(defcustom mutt-uses-fill-mode t
+  "*Specifies whether Mutt should automatically wrap lines.
+Set this to t to enable line wrapping, and nil to disable line
+wrapping. Note that if a paragraph gets messed up (the line wrapper
+is very primitive), you can type \\[fill-paragraph] to rewrap the paragraph."
+  :type 'boolean
+  :group 'mutt)
+
+(defcustom mutt-signature-pattern "\\(--\\|Cheers,\\|\f\\)"
+  "*Pattern for identifying signatures.
+Mutt uses this to locate signatures. It should contain no leaading or
+trailing whitespace."
+  :type 'string
+  :group 'mutt)
+
+(defcustom mutt-file-pattern "mutt-[a-z]+-[0-9]+-[0-9]+\\'"
+  "*Regular expression which matches Mutt's temporary files."
+  :type 'string
+  :group 'mutt)
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Customizable Faces
+;;; The dark background versions are probably uglier than the light
+;;; (which I use). If you find a more attractive, subdued color scheme,
+;;; please mail it to me.
+
+(defgroup mutt-faces nil
+  "Typefaces used for composing messages with Mutt."
+  :group 'mutt
+  :group 'faces)
+
+(defface mutt-header-keyword-face
+  '((((class color)
+      (background light))
+     (:foreground "Navy" :bold t))
+    (((class color)
+      (background dark))
+     (:foreground "LightBlue" :bold t))
+    (t
+     (:bold t)))
+  "Face used for displaying keywords (e.g. \"From:\") in headers."
+  :group 'mutt-faces)
+
+(defface mutt-header-value-face
+  '((((class color)
+      (background light))
+     (:foreground "MidnightBlue"))
+    (((class color)
+      (background dark))
+     (:foreground "LightSteelBlue")))
+  "Face used for displaying the values of headers."
+  :group 'mutt-faces)
+
+(defface mutt-quoted-text-face
+  '((((class color)
+      (background light))
+     (:foreground "Sienna" :italic t))
+    (((class color)
+      (background dark))
+     (:foreground "Wheat" :italic t))
+    (t
+     (:bold t :italic t)))
+  "Face used for displaying text which has been quoted (e.g. \">foo\")."
+  :group 'mutt-faces)
+
+(defface mutt-multiply-quoted-text-face
+  '((((class color)
+      (background light))
+     (:foreground "Firebrick" :italic t))
+    (((class color)
+      (background dark))
+     (:foreground "Tan" :italic t))
+    (t
+     (:italic t)))
+  "Face used for text which has been quoted more than once (e.g. \">>foo\")."
+  :group 'mutt-faces)
+
+(defvar mutt-font-lock-keywords
+  '(("^\\([A-Z][-A-Za-z0-9.]+:\\)\\(.*\\)$"
+     (1 'mutt-header-keyword-face)
+     (2 'mutt-header-value-face))
+    ("^[ \t\f]*\\(>[ \t\f]*[^ \t\f>].*\\)$"
+     (1 'mutt-quoted-text-face))
+    ("^[ \t\f]*\\(>[ \t\f]*\\)\\(>.*\\)$"
+     (1 'mutt-quoted-text-face)
+     (2 'mutt-multiply-quoted-text-face)))
+  "Highlighting rules for message mode.")
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Interactive Commands
+
+(defun mutt-save-current-buffer-and-exit ()
+  "Save the current buffer and exit Emacs."
+  (interactive)
+  (basic-save-buffer)
+  (save-buffers-kill-emacs))
+
+(defun mutt-delete-quoted-signatures ()
+  "Delete quoted signatures from buffer."
+  (interactive)
+  (goto-char (point-min))
+  (flush-lines (concat "^\\([ \t\f]*>[ \t\f>]*\\)"
+                      mutt-signature-pattern
+                      "[ \t\f]*\\(\n\\1.*\\)*")))
+
+(defun mutt-delete-old-citations ()
+  "Delete citations more than one level deep from buffer."
+  (interactive)
+  (goto-char (point-min))
+  (flush-lines "^[ \t\f]*>[ \t\f]*>[ \t\f>]*"))
+
+(defun mutt-goto-body ()
+  "Go to the beginning of the message body."
+  (interactive)
+  (goto-char (point-min))
+  ;; If the message has headers, slide downward.
+  (and headers-mode
+       (save-match-data (re-search-forward "^$" nil t))
+       (next-line 1)))
+
+(defun mutt-goto-signature ()
+  "Go to the beginning of the message signature."
+  (interactive)
+  (goto-char (point-max))
+  (and (save-match-data
+        (re-search-backward (concat "^" mutt-signature-pattern
+                                    "[ \t\f]*$")
+                            nil t))
+       (previous-line 1)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Mutt Mode Meat
+
+(define-derived-mode mutt-mode text-mode "Mutt"
+  "Major mode for composing E-mail with the Mutt mailer.
+To customize it, type \\[customize] and select [Applications] [Mail] [Mutt].
+When you finish editing this message, type \\[mutt-save-current-buffer-and-exit] to save and exit Emacs.
+
+\\{mutt-mode-map}"
+
+  (rename-buffer "*Composing*" t)
+  (auto-fill-mode (if mutt-uses-fill-mode 1 0))
+
+  ;; Make Emacs smarter about wrapping citations and paragraphs.
+  ;; We probably can't handle Supercited messages, though.
+  (make-local-variable 'paragraph-start)
+  (make-local-variable 'paragraph-separate)
+  (setq paragraph-start
+       "\\([ \t\n\f]+[^ \t\n\f>]\\|[ \t\f>]*$\\)"
+       paragraph-separate
+       "[ \t\f>]*$")
+
+  ;; If Mutt passed us headers, activate the necessary commands.
+  (when (looking-at "^[-A-Za-z0-9]+:")
+    (headers-mode 1))
+
+  ;; Our temporary file lives in /tmp. Yuck! Compensate appropriately.
+  (make-local-variable 'backup-inhibited)
+  (setq backup-inhibited t)
+  (cd "~")
+
+  (make-local-variable 'font-lock-defaults)
+  (setq font-lock-defaults '(mutt-font-lock-keywords t))
+
+  (mutt-goto-body)
+  (message (substitute-command-keys "Type \\[describe-mode] for help composing; \\[mutt-save-current-buffer-and-exit] when done.")))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Mutt Headers Mode
+
+(defvar headers-mode nil)
+
+(defun headers-mode (&optional arg)
+  "Commands for editing the headers of an e-mail or news message.
+
+\\{headers-mode-map}"
+
+  (interactive "P")
+  (make-local-variable 'headers-mode)
+  (setq headers-mode
+       (if (null arg)
+           (not headers-mode)
+         (> (prefix-numeric-value arg) 0)))
+  (force-mode-line-update))
+
+(defvar headers-mode-map (make-sparse-keymap)
+  "Keymap used for editing RFC822 headers.")
+
+(defun headers-position-on-value ()
+  (beginning-of-line)
+  (skip-chars-forward "-A-Za-z0-9:")
+  ;; XXX - Should make sure we stay on line.
+  (forward-char))
+
+(defun headers-goto-field (field)
+  (let ((case-fold-search t))
+    (goto-char (point-min))
+    (save-match-data
+      (when (re-search-forward (concat "^\\($\\|" field ": \\)"))
+       (if (looking-at "^$")
+           (progn
+             (insert-string field ": \n")
+             (forward-char -1))
+         (headers-position-on-value))))))
+
+(defmacro define-header-goto (name header)
+  `(defun ,name ()
+     ,(concat "Position the cursor on the " header ": header.")
+     (interactive)
+     (headers-goto-field ,header)))
+
+(define-header-goto headers-goto-to "To")
+(define-header-goto headers-goto-cc "Cc")
+(define-header-goto headers-goto-fcc "Fcc")
+(define-header-goto headers-goto-summary "Summary")
+(define-header-goto headers-goto-keywords "Keywords")
+(define-header-goto headers-goto-subject "Subject")
+(define-header-goto headers-goto-bcc "Bcc")
+(define-header-goto headers-goto-reply-to "Reply-To")
+(define-header-goto headers-goto-from "From")
+(define-header-goto headers-goto-organization "Organization")
+
+(defun headers-attach-file (file description)
+  "Attach a file to the current message (works with Mutt)."
+  (interactive "fAttach file: \nsDescription: ")
+  (when (> (length file) 0)
+    (save-excursion
+      (save-match-data
+       (save-restriction
+         (widen)
+         (goto-char (point-min))
+         (search-forward-regexp "^$")
+         (insert-string (concat "Attach: " (file-truename file) " "
+                                description "\n"))
+         (message (concat "Attached '" file "'.")))))))
+
+(or (assq 'headers-mode minor-mode-alist)
+    (setq minor-mode-alist
+         (cons '(headers-mode " Headers") minor-mode-alist)))
+
+(or (assq 'headers-mode minor-mode-map-alist)
+    (setq minor-mode-map-alist
+         (cons (cons 'headers-mode headers-mode-map)
+               minor-mode-map-alist)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Key Bindings
+
+(define-key mutt-mode-map "\C-c\C-c" 'mutt-save-current-buffer-and-exit)
+(define-key mutt-mode-map "\C-c\C-d\C-s" 'mutt-delete-quoted-signatures)
+(define-key mutt-mode-map "\C-c\C-d\C-c" 'mutt-delete-old-citations)
+(define-key mutt-mode-map "\C-c\C-b" 'mutt-goto-body)
+(define-key mutt-mode-map "\C-c\C-i" 'mutt-goto-signature)
+
+(define-key headers-mode-map "\C-c\C-f\C-t" 'headers-goto-to)
+(define-key headers-mode-map "\C-c\C-f\C-c" 'headers-goto-cc)
+(define-key headers-mode-map "\C-c\C-f\C-w" 'headers-goto-fcc)
+(define-key headers-mode-map "\C-c\C-f\C-u" 'headers-goto-summary)
+(define-key headers-mode-map "\C-c\C-f\C-k" 'headers-goto-keywords)
+(define-key headers-mode-map "\C-c\C-f\C-s" 'headers-goto-subject)
+(define-key headers-mode-map "\C-c\C-f\C-b" 'headers-goto-bcc)
+(define-key headers-mode-map "\C-c\C-f\C-r" 'headers-goto-reply-to)
+(define-key headers-mode-map "\C-c\C-f\C-f" 'headers-goto-from)
+(define-key headers-mode-map "\C-c\C-f\C-o" 'headers-goto-organization)
+(define-key headers-mode-map "\C-c\C-a" 'headers-attach-file)
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Menus
+
+(easy-menu-define
+ mutt-mode-menu mutt-mode-map "Mutt Message Composition Commands." 
+ '("Mutt"
+   ["Delete Quoted Signatures" mutt-delete-quoted-signatures t]
+   ["Delete Doubly-Quoted Text" mutt-delete-old-citations t]
+   "----"
+   ["Go To Body of Message" mutt-goto-body t]
+   ["Go To Signature of Message" mutt-goto-signature t]
+   "----"
+   ["Save Message and Return to Mutt" mutt-save-current-buffer-and-exit t]))
+
+(easy-menu-define
+ headers-mode-menu headers-mode-map "Header Editing Commands."
+ '("Headers"
+   ["Attach File..." headers-attach-file t]
+   "----"
+   ["Edit From Header" headers-goto-from t]
+   ["Edit Subject Header" headers-goto-subject t]
+   ["Edit To Header" headers-goto-to t]
+   ["Edit Cc Header" headers-goto-cc t]
+   ["Edit Bcc Header" headers-goto-bcc t]
+   ["Edit Fcc Header" headers-goto-fcc t]
+   ["Edit Reply-To Header" headers-goto-reply-to t]
+   ["Edit Summary Header" headers-goto-summary t]
+   ["Edit Keywords Header" headers-goto-keywords t]
+   ["Edit Organization Header" headers-goto-organization t]))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Finish Installing Mutt Mode
+
+(unless (assq mutt-file-pattern auto-mode-alist)
+  (setq auto-mode-alist
+       (cons (cons mutt-file-pattern 'mutt-mode)
+             auto-mode-alist)))
+
+(provide 'mutt)
diff --git a/emacs_el/post.el b/emacs_el/post.el
new file mode 100644 (file)
index 0000000..6c1cade
--- /dev/null
@@ -0,0 +1,1397 @@
+;      $Id: post.el,v 2.4 2004/07/23 23:13:17 rreid Exp rreid $
+;; post.el --- Use (X?)Emacs(client) as an external editor for mail and news.
+;;; Authors: Eric Kidd <eric.kidd@pobox.com>,
+;;;          Dave Pearson <davep@davep.org>,
+;;;          Rob Reid <reid@astro.utoronto.ca>,
+;;;          Roland Rosenfeld <roland@spinnaker.de>
+
+;; This is free software distributed under the GPL, yadda, yadda, yadda.
+;; It has no warranty. See the GNU General Public License for more
+;; information. Send us your feature requests and patches, and we'll try
+;; to integrate everything.
+
+;;; Maintainer: Rob Reid <reid@astro.utoronto.ca>
+
+;;; Keywords: mail
+
+;;; Commentary:
+;; This is a major mode for use with Mutt, the spiffy *nix mailreader du jour
+;; (See http://www.mutt.org/), slrn, the spiffy *nix newsreader du jour, or
+;; whatever you can get it to work with.  To use this mode, add the following
+;; line to the .emacs file in your home directory:
+;;
+;;   (load "/your/local/path/to/this/file/post")
+;;
+;; Note that you can omit the ".el" from the file name when calling load.
+;;
+;; If you want to make it available to all your users, type \C-h v
+;; load-path RET, pick an appropriate directory for post.el, and modify
+;; your sitewide default.el to (require 'post).
+;;
+;; You may find the latest version of this mode at
+;; http://astro.utoronto.ca/~reid/mutt/
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; BUGS:
+;;
+;; Rob: I predict that some buffers (*Original*<2>, *Composing*<2>?)
+;; will be left behind if you edit more than one message at a time.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Thanks
+;;;
+;;; Dave Pearson: Code, feature ideas, Mutt experience. Many thanks!
+;;; Louis Theran: Encouragement to make Mutt mode work like Emacs MUAs.
+;;; Ronald: Enlightening gripes about what Emacs should do, but doesn't.
+;;; Robert Napier: Bug reports about font-lock mode, fancy wrapping.
+;;; Kevin Rodgers: Answered RR's question on gnu.emacs.help on
+;;; overwriting server-process-filter's annoying message at startup.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Revision History
+;;;
+;;; $Log: post.el,v $
+;;; Revision 2.401  2004/07/23 16:27:29  rreid
+;;; Fixed post-delete-quoted-signatures to not remove sneaky things like quoted
+;;; double dash arrows.  Thanks go to Felix Klee for a clear bug report.
+;;;
+;;; Revision 2.4  2002/04/22 22:04:29  reid
+;;; Tweaked post-emoticon-pattern yet again.  Made cl mandatory for all
+;;; versions of emacs.  (Thanks to Eric Dorland and Mike Schiraldi for bug
+;;; reports.)  Fixed post-unquote-region.  (Thanks to Mike Schiraldi for the
+;;; bug report.)
+;;;
+;;; Revision 2.3  2002/04/21 20:13:55  reid
+;;; Improved post-emoticon-pattern.
+;;;
+;;; Revision 2.2  2002/04/20 04:12:54  reid
+;;; Improved post-emoticon-pattern.
+;;;
+;;; Revision 2.1  2002/04/20 03:17:48  reid
+;;; - A major (but not total) synchronization with Dave Pearson's post-mode.
+;;;   header-set-followup-to and header-set-organization should work now.
+;;; - Syntax highlighting now works for quoted email addresses and URLs.
+;;; - *bold* words are now highlighted.
+;;; - Emoticons can now be highlighted, and the default regexp,
+;;;   post-emoticon-pattern, might be too enthusiastic for your taste.  In case
+;;;   you're curious, I verified that gnus' smiley-ems.el works with post, but I
+;;;   decided that it wasn't ideal.
+;;; - post-url-text-pattern changed to post-url-pattern and made more enthusiastic.
+;;;
+;;; revision 1.95 2002/04/10 00:06:26 reid
+;;; Fixed the regexp in post-kill-signature to not delete everything between
+;;; mutt's standard forwarding lines.  post-kill-signature is called indirectly
+;;; by many functions.
+;;;
+;;; Revision 1.9  2002/04/04 22:24:31  reid
+;;; Applied a patch (not quite verbatim) from The Anarcat
+;;; <anarcat@anarcat.dyndns.org> to make the entity separating siglets in
+;;; `post-variable-signature-source' a regexp, `post-signature-sep-regexp'.  The
+;;; default works either either the old post file format or strfiled (fortune)
+;;; files.
+;;;;
+;;; Changed default `post-random-signature-command' to `fortune
+;;; ~/.mutt/sigs.fortune'.
+;;;
+;;; `post-random-signature-command' should now NOT supply a fixed sig portion!
+;;;
+;;; (post-el-random-signature) supplied by The Anarcat to do random sig
+;;; selection purely within Emacs Lisp.
+;;;
+;;; Revision 1.8  2002/02/06 22:24:31  eric
+;;; clean up
+;;;
+;;; Revision 1.7.2  2002/02/06 22:17:01  eric
+;;; tweak regexps, make font-lock-comment-face be post-signature-text-face
+;;;
+;;; Revision 1.7.1  2002/02/06 21:58:58  eric
+;;; tweak regexp, change some types to regexp
+;;;
+;;; Revision 1.7.0  2002/02/06 21:36:56  eric
+;;; hilight signatures, urls and emails
+;;;
+;;; Revision 1.6.3.10  1999/10/11 00:29:41  roland
+;;; Corrected color quoting again: Now allows ">" in the middle of
+;;; a line which is quoted twice.
+;;;
+;;; Revision 1.6.3.9  1999/10/08 10:43:18  roland
+;;; Add third level of quoting faces.
+;;; Allow super-cite name prefixes before quote signs.
+;;;
+;;; Revision 1.6.3.8  1999/10/08 08:39:00  roland
+;;; post-font-lock-keywords now detects lines with only "> "in it
+;;; correctly (merged following line into it before).
+;;;
+;;; Revision 1.6.3.7  1999/10/04 10:07:48  roland
+;;; Add post-quote-region and post-unquote-region commands to quote and
+;;; unquote a region (one level).
+;;;
+;;; Revision 1.6.3.6  1999/09/03 23:13:55  reid
+;;; Valeriy E. Ushakov <uwe@ptc.spbu.ru> pointed out that (GNU) Emacs <20 has
+;;; fewer (optional) arguments to (read-string) than what I was using to
+;;; inherit the input method.  I didn't find a way off the top of my head
+;;; to redefine (read-string) without causing an infinite loop, so I have
+;;; substituted a macro (string-read prompt) which does the right thing,
+;;; so please use it instead of read-string.
+;;;
+;;; Revision 1.6.3.5  1999/08/29 19:58:49  reid
+;;; Changed default post-mail-message to handle hostnames with digits.
+;;; Thanks to Brian D. Winters <brianw@alumni.caltech.edu>.
+;;;
+;;; Revision 1.6.3.4  1999/03/20 03:02:05  reid
+;;; Made post compatible with emacs as far back as 19.28.1, probably
+;;; farther.
+;;;
+;;; Revision 1.6.3.3  1999/03/16 03:14:07  reid
+;;; Cleaned up post-select-signature-select-sig-from-file code.
+;;;
+;;; Revision 1.6.3.2  1999/03/16 03:05:12  reid
+;;; Fixed alist updating.
+;;;
+;;; Revision 1.6.3.1  1999/03/13 02:23:48  reid
+;;; Added defface to the list of things that get defined if customize
+;;; hasn't already done it.  Thanks to Melissa Binde for the bug report.
+;;;
+;;; Modified post-body-says-attach to use a regexp,
+;;; post-attachment-regexp, so that something like "\(attach\|anbringen\)"
+;;; can be used by bilingual people like Roland.
+;;;
+;;; Revision 1.6.2.1  1999/03/12 10:16:11  roland
+;;; Added missing () to post-insert-to-auto-mode-alist-on-load.
+;;;
+;;; Revision 1.6.2 1999/03/11 15:51 Dave Pearson
+;;; header-position-on-value fixed to return (point), and
+;;; defcustom macro provided for Emacs 19 users.
+;;;
+;;; Revision 1.6.1.2  1999/03/06 11:24:43  roland
+;;; Added post-insert-to-auto-mode-alist-on-load.
+;;;
+;;; Revision 1.6.1.1  1999/03/06 11:02:27  roland
+;;; Customized renaming of buffer.
+;;; Removed different handling for mail, news, news-reply.
+;;; Fixed problems with easy-menu under XEmacs.
+;;;
+;;; Revision 1.6.0 1999/03/04 18:04 Rob Reid
+;;; Returned post-signature-pattern to using "--" instead of "-- "
+;;; because some senders have broken MTAs (as Eric reminded me) and
+;;; some users don't use procmail to compensate.  This time all of the
+;;; functions dealing with signatures have been smartened up to avoid
+;;; false matches.  Unfortunately that means they don't use
+;;; post-signature-pattern in its raw form.
+;;;
+;;; Added post-backup-original so that Dave's post-copy-original can
+;;; be used.
+;;;
+;;; Kevin Rodgers explained how to put this in .emacs to fix the
+;;; server-process-filter's annoying message problem:
+;;;
+;;; Revision 1.1  1999/03/04 18:02:30  reid
+;;; Initial revision
+;;;
+;;; %%%%%%%%%%%% Put in .emacs %%%%%%%%%%%
+;;;
+;;; ;;; Email
+;;; (server-start)
+;;; (load "/home/reid/.mutt/post")
+;;; (defadvice server-process-filter (after post-mode-message first activate)
+;;;    "If the buffer is in post mode, overwrite the server-edit
+;;;    message with a post-save-current-buffer-and-exit message."
+;;;    (if (eq major-mode 'post-mode)
+;;;        (message
+;;;         (substitute-command-keys "Type \\[describe-mode] for help composing; \\[post-save-current-buffer-and-exit] when done."))))
+;;; ; This is also needed to see the magic message.  Set to a higher
+;;; ; number if you have a faster computer or read slower than me.
+;;; '(font-lock-verbose 1000)
+;;; ; (setq server-temp-file-regexp "mutt-")
+;;; (add-hook 'server-switch-hook
+;;;         (function (lambda()
+;;;                     (cond ((string-match "Post" mode-name)
+;;;                            (post-goto-body))))))
+;;;
+;;; %%%%%%%%% We now return to our regular commentary %%%%%%%%%
+;;;
+;;; Eric Kidd asked that the name of Headers mode be changed so that
+;;; it doesn't conflict with mutt-mode's Headers, so I changed it to
+;;; just Header (no s).
+;;;
+;;; Revision 1.5? 1999/02/27 17:30 Rob Reid
+;;; I had a go at combining Dave Pearson's post mode with Eric Kidd's
+;;; Mutt mode.  Since Dave Pearson's post mode explicitly handles news as
+;;; well as email, and this should be useful for more than just mutt,
+;;; I'm calling it post mode.  I also added functions for picking
+;;; random signatures, selecting a signature from a file, and
+;;; intelligently (IMHO) prompting the user for an attachment when
+;;; necessary.  Changed mutt-save-buffer-and-exit to work better with
+;;; emacsclient, and some of the key bindings.  post-signature-pattern
+;;; now defaults to use "-- " instead of "--", and I have far less
+;;; trouble this way (I use procmail to clean up braindead "--"s.).  I
+;;; don't know why Eric warned against trailing whitespace.
+;;;
+;;; Revision 1.4  1998/04/11 00:05:46  emk
+;;; Fixed font-lock bug. Also made mutt-mode a little more careful about
+;;; saving various bits of Emacs state when moving around the buffer.
+;;;
+;;; Revision 1.3  1998/03/25 00:37:36  emk
+;;; Added support for menus and font-lock mode, plus a few bug fixes.
+;;;
+;;; Revision 1.2  1998/03/24 13:19:46  emk
+;;; Major overhaul--more commands, a minor mode for header editing, and other
+;;; desirable features. Attaching files seems to be broken, though.
+;;;
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Required Packages
+
+(require 'cl)
+(require 'derived)
+(require 'easymenu)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Customization Support
+;;;
+;;; Set up our customizable features. You can edit these (and lots of other
+;;; fun stuff) by typing M-x customize RET. The Post preferences can be
+;;; found under the [Applications] [Mail] category.
+
+;; Make post mode a bit more compatible with older (i.e. <20) versions of emacs.
+;;; Code:
+(eval-and-compile
+  ;; Dumb down read-string if necessary.
+  ;; The number of optional arguments for read-string seems to increase
+  ;; sharply with (emacs-version).  Since old versions of emacs are a large
+  ;; source of bug reports it might be worth writing (or looking for)
+  ;; (bug-report reid@astro.utoronto.ca) which emails me the result of
+  ;; (emacs-version) along with a user supplied description of the problem.
+  ;; GNU Emacs 19.28.1 only has INITIAL-STRING as an optional argument.
+  ;; 19.34.1 has (read-string PROMPT &optional INITIAL-INPUT HISTORY).  20.2.1
+  ;; has (read-string PROMPT &optional INITIAL-INPUT HISTORY DEFAULT-VALUE
+  ;; INHERIT-INPUT-METHOD).
+  ;; Since I haven't found a way of redefining read-string without causing an
+  ;; infinite loop, please use (string-read prompt).
+  (if (< (string-to-number (substring (emacs-version)
+                                     (string-match "[0-9]+\.[0-9]"
+                                        (emacs-version) 5))) 20)
+      (defmacro string-read (prompt) (` (read-string (, prompt))))
+      (defmacro string-read (prompt)
+       (` (read-string (, prompt) nil nil nil t))))
+
+  ;; XEmacs gnuserv uses slightly different functions than the GNU Emacs
+  ;; server, and some people are still wasting time and CPU cycles by starting
+  ;; up a new emacs each time.
+  (cond ((fboundp 'server-edit)
+        (fset 'post-finish 'server-edit))
+       ((fboundp 'gnuserv-kill-buffer-function)
+        (fset 'post-finish 'gnuserv-kill-buffer-function))
+       (t
+        (fset 'post-finish 'save-buffers-kill-emacs)))
+   
+  ;; If customize isn't available just use defvar instead.
+  (unless (fboundp 'defgroup)
+    (defmacro defgroup  (&rest rest) nil)
+    (defmacro defcustom (symbol init docstring &rest rest)
+      ; The "extra" braces and whitespace are for emacs < 19.29.
+      (` (defvar (, symbol) (, init) (, docstring))))
+    (defmacro defface (&rest args) nil))
+  (unless (fboundp 'buffer-substring-no-properties)
+    (fset 'buffer-substring-no-properties 'buffer-substring)))
+
+(defgroup post nil
+  "Composing e-mail messages with Post.
+Emacs can run as an external editor for Mutt, the spiffy Unix mail reader
+du jour, or slrn, the spiffy Unix news reader du jour.  You can get
+Mutt from http://www.mutt.org/."
+  :group 'mail)
+
+(defcustom post-uses-fill-mode t
+  "*Specifies whether Post should automatically wrap lines.
+Set this to t to enable line wrapping, and nil to disable line
+wrapping.  Note that if a paragraph gets messed up (the line wrapper
+is very primitive), you can type \\[fill-paragraph] to rewrap the paragraph."
+  :type 'boolean
+  :group 'post)
+
+(defcustom post-mail-message "mutt-[a-z0-9]+-[0-9]+-[0-9]+\\'"
+  "*Regular expression which matches your mailer's temporary files."
+  :type 'string
+  :group 'post)
+
+(defcustom post-news-posting "\\.\\(followup\\|letter\\|article\\)$"
+  "*Regular expression which matches your news reader's composition files."
+  :type 'string
+  :group 'post)
+
+(defcustom post-backup-original nil
+  "*Controls whether a pristine backup of the original is kept for reference."
+  :type 'boolean
+  :group 'post)
+
+(defcustom post-signature-pattern "\\(--\\|Cheers,\\|\f\\)"
+  "*Pattern signifying the beginning of signatures.
+It should not contain trailing whitespace unless you know what you're doing."
+  :type 'regexp
+  :group 'post)
+
+(defcustom post-signature-sep-regexp "^\\(%\\|^L\\|--\\)?\n"
+  "*Regular expression delimiting signatures in the signature file.
+This allows the use of classic fortune files as signature files.
+This should normally contain a newline."
+  :type 'regexp
+  :group 'post)
+
+(defcustom post-signature-source-is-file t
+  "*Toggles the signature source type between file and directory."
+  :type 'boolean
+  :group 'post)
+
+(defcustom post-variable-signature-source "~/.mutt/sigs.fortune"
+  "*Location of the variable part of your signature.
+Post uses this to locate signatures.  It can be either a directory
+with one item per file or a file with items separated by blank lines."
+  :type 'string
+  :group 'post)
+
+(defcustom post-fixed-signature-source "~/.fixedsig"
+  "*File with the fixed part of your signature."
+  :type 'string
+  :group 'post)
+
+(defcustom post-signature-directory "~/.sigs/"
+  "*The directory that contains your collection of signature files."
+  :type 'string
+  :group 'post)
+
+(defcustom post-signature-wildcard "sig*"
+  "*Wildcard for finding signature files in your signature directory."
+  :type 'string
+  :group 'post)
+
+(defcustom post-random-signature-command "fortune ~/.mutt/sigs.fortune"
+  "*Command to run to get a random signature.
+Examples are available at http://astro.utoronto.ca/~reid/mutt/"
+  :type 'string
+  :group 'post)
+
+(defcustom post-kill-quoted-sig t
+  "Specifies whether `post-mode' should automatically kill quoted signatures."
+  :type 'boolean
+  :group 'post)
+
+(defcustom post-jump-header t
+  "Specifies wheather `post-mode' should jump to the body."
+  :type 'boolean
+  :group 'post)
+
+(defcustom post-force-pwd-to-home t
+  "Specifies whether `post-mode' should cd to your home directory."
+  :type 'boolean
+  :group 'post)
+
+(defcustom post-email-address (concat (user-login-name) "@" mail-host-address)
+  "*Your email address."
+  :type 'string
+  :group 'post)
+
+(defcustom post-should-prompt-for-attachment 'Smart
+  "*Controls whether an attachment will be prompted for before saving
+the message and exiting.  'Smart' will prompt only if the body
+contains post-attachment-regexp."
+  :type '(choice (const Never)
+                (const Smart)
+                (const Always))
+  :group 'post)
+
+(defcustom post-attachment-regexp "attach"
+  "*This is what post looks for in the body if
+post-should-prompt-for-attachment is 'Smart'."
+  :type 'regexp
+  :group 'post)
+
+(defcustom post-news-poster-regexp "^On .*<.*>.*wrote:$"
+  "Regular expression used to locate the attribution line of a news posting."
+  :type 'regexp
+  :group 'post)
+
+(defcustom post-rename-buffer t
+  "Specify whether `post-mode' should rename the buffer to *Composing*."
+  :type 'boolean
+  :group 'post)
+
+(defcustom post-insert-to-auto-mode-alist-on-load t
+  "Automatically insert `post-mode' with `post-mail-message' to `auto-mode-alist'."
+  :type 'boolean
+  :group 'post)
+
+(defcustom post-mode-hook nil
+  "List of hooks to be executed on entry to `post-mode'."
+  :group 'post)
+
+(defcustom post-quote-start "> "
+  "Pattern which is added (or removed) at the beginning of the line by
+comment-region"
+  :group 'post)
+
+(defcustom post-email-address-pattern
+  "[A-Za-z0-9_][-A-Za-z0-9._]*@[-A-Za-z0-9._]*[A-Za-z0-9]"
+  "Pattern to detect email addresses."
+  :type 'regexp
+  :group 'post)
+
+(defcustom post-url-pattern
+  '("\\<\\(\\(https?\\|news\\|mailto\\|ftp\\|gopher\\):\\|\\(www\\|ftp\\)\\.\\)[-~A-Za-z0-9._/%$+?#]+[A-Za-z0-9/#]" "<URL:[^ ]+>")
+  "Pattern to detect URL addresses."
+  :type '(repeat regexp)
+  :group 'post)
+
+(defcustom post-bold-pattern '("\\*\\w+\\*")
+  "*List of regular expressions that define bold text."
+  :type '(repeat regexp)
+  :group 'post)
+
+(defcustom post-underline-pattern '("_\\w+_")
+  "*List of regular expressions that define underlined text."
+  :type '(repeat regexp)
+  :group 'post)
+
+(defcustom post-emoticon-pattern '("[0O(<{}]?[;:8B|][.,]?[-+^*o0O][{<>/\|]?[][)>(<|/\P][)>]?"
+                       "\\s [(<]?[][)>(<|/\][}<>|]?[-+^*oO0][,.]?[:8][0O>]?"
+                       "\\s [;:][][P)\/(]" "\\s [][)(P\/][:;]"
+                                  "<[Gg]>" "<[BbSs][Gg]>")
+  "*List of regular expressions that define a emoticon."
+  :type '(repeat regexp)
+  :group 'post)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Customizable Faces
+;;; If you find a more attractive color scheme for dark backgrounds, please
+;;; email it to reid@astro.utoronto.
+
+(defgroup post-faces nil
+  "Typefaces used for composing messages with Post."
+  :group 'post
+  :group 'faces)
+
+(defface post-header-keyword-face
+  '((((class color)
+      (background light))
+     (:foreground "Navy" :bold t))
+    (((class color)
+      (background dark))
+     (:foreground "LightBlue" :bold t))
+    (t
+     (:bold t)))
+  "Face used for displaying keywords (e.g. \"From:\") in header."
+  :group 'post-faces)
+
+(defface post-header-value-face
+  '((((class color)
+      (background light))
+     (:foreground "MidnightBlue"))
+    (((class color)
+      (background dark))
+     (:foreground "LightSteelBlue")))
+  "Face used for displaying the values of header."
+  :group 'post-faces)
+
+(defface post-quoted-text-face
+  '((((class color)
+      (background light))
+     (:foreground "Sienna" :italic t))
+    (((class color)
+      (background dark))
+     (:foreground "Wheat" :italic t))
+    (t
+     (:bold t :italic t)))
+  "Face used for displaying text which has been quoted (e.g. \">foo\")."
+  :group 'post-faces)
+
+(defface post-double-quoted-text-face
+  '((((class color)
+      (background light))
+     (:foreground "Firebrick" :italic t))
+    (((class color)
+      (background dark))
+     (:foreground "Tan" :italic t))
+    (t
+     (:italic t)))
+  "Face used for text which has been quoted twice (e.g. \">>foo\")."
+  :group 'post-faces)
+
+(defface post-multiply-quoted-text-face
+  '((((class color)
+      (background light))
+     (:foreground "goldenrod" :italic t))
+    (((class color)
+      (background dark))
+     (:foreground "tan3" :italic t))
+    (t
+     (:italic t)))
+  "Face used for text which has been quoted more than twice (e.g. \">>>foo\")."
+  :group 'post-faces)
+
+(defface post-signature-text-face
+  '((((class color)
+      (background light))
+     (:foreground "red3"))
+    (((class color)
+      (background dark))
+     (:foreground "red1"))
+    (t
+     (:bold t)))
+  "Face used for text that is part of a signature"
+  :group 'post-faces)
+
+(defface post-email-address-text-face
+  '((((class color)
+      (background light))
+     (:foreground "green3"))
+    (((class color)
+      (background dark))
+     (:foreground "green1"))
+    (t
+     (:italic t)))
+  "Face used for email addresses"
+  :group 'post-faces)
+
+(defface post-url-face
+  '((((class color)
+      (background light))
+     (:foreground "green3" :bold t))
+    (((class color)
+      (background dark))
+     (:foreground "green1" :bold t))
+    (t
+     (:italic t)))
+  "Face used for URL addresses"
+  :group 'post-faces)
+
+(defface post-emoticon-face
+  '((((class color)
+      (background light))
+     (:foreground "black" :background "yellow" :bold t))
+    (((class color)
+      (background dark))
+     (:foreground "black" :background "yellow" :bold t))
+    (t
+     (:bold t)))
+  "Face used for text matched by post-emoticon-pattern."
+  :group 'post-faces)
+
+(defface post-bold-face
+  '((((class color)
+      (background light))
+     (:bold t))
+    (((class color)
+      (background dark))
+     (:bold t))
+    (t
+     (:bold t)))
+  "Face used for text matching post-bold-pattern."
+  :group 'post-faces)
+
+(defface post-underline-face
+  '((((class color)
+      (background light))
+     (:underline t))
+    (((class color)
+      (background dark))
+     (:underline t))
+    (t
+     (:underline t)))
+  "Face used for text matching post-underline-pattern."
+  :group 'post-faces)
+
+; Note: some faces are added later!
+(defvar post-font-lock-keywords
+  `(("^\\([A-Z][-A-Za-z0-9.]+:\\)\\(.*\\)$"
+     (1 'post-header-keyword-face)
+     (2 'post-header-value-face))
+    ("^[ \t\f]*\\(>[ \t\f]*\\)\\([-a-zA-Z]*>[ \t\f]*\\)\\([-a-zA-Z]*>.*\\)$"
+     (1 'post-quoted-text-face)
+     (2 'post-double-quoted-text-face)
+     (3 'post-multiply-quoted-text-face))
+    ("^[ \t\f]*\\(>[ \t\f]*\\)\\([-a-zA-Z]*>.*\\)$"
+     (1 'post-quoted-text-face)
+     (2 'post-double-quoted-text-face))
+    ("^[ \t\f]*\\(>[ \t\f]*[^ \t\f\n>].*\\)$"
+     (1 'post-quoted-text-face))
+    ("^[ \t\f]*\\(>[ \t\f]*\\)$"
+     (1 'post-quoted-text-face))
+       (,post-email-address-pattern
+        (0 'post-email-address-text-face)))
+  "Highlighting rules for message mode.")
+
+;;; Declare global mode variables.
+
+(defconst post-font-lock-syntactic-keywords
+  `((,(concat "^" post-signature-pattern "[ \t\f]*$") 0 '(11))))
+
+(defun post-font-lock-syntactic-face-function (state)
+  "Function for font locking syntactic faces.
+Argument STATE ."
+post-signature-text-face)
+
+(defvar post-buf nil
+  "Name of the composing buffer.")
+
+(defvar post-select-signature-mode-map nil
+  "Local keymap for the select-signature buffer.")
+
+(defvar post-select-signature-last-buffer nil
+  "Pointer to the calling buffer.")
+
+(defvar post-select-signature-last-point nil
+  "Where we were in the calling buffer.")
+
+(defvar post-has-attachment nil
+ "Whether the message has an attachment.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Interactive Commands
+
+(defun post-save-current-buffer-and-exit ()
+  "Save the current buffer and exit Emacs."
+  (interactive)
+
+  ;; Should the user be prompted for an attachment?
+  (cond (post-has-attachment)
+       ((equal post-should-prompt-for-attachment 'Never))
+       ((or (equal post-should-prompt-for-attachment 'Always)
+            (post-body-says-attach))
+        (post-prompt-for-attachment)))
+
+  (basic-save-buffer)
+
+  (if post-backup-original
+      (kill-buffer "*Original*"))
+
+  (post-finish)
+
+  ;; Added by Rob Reid 10/13/1998 to prevent accumulating *Composing* buffers
+  ;; when using (emacs|gnu)client.  Helped by Eric Marsden's Eliza example in
+  ;; http://www.ssc.com/lg/issue29/marsden.html
+  (kill-buffer post-buf))
+
+(defun post-goto-body ()
+  "Go to the beginning of the message body."
+  (interactive)
+  (goto-char (point-min))
+  ;; If the message has header, slide downward.
+  (and header-mode (save-match-data (re-search-forward "^$" nil t))
+       (next-line 1)))
+
+(defun post-goto-signature ()
+  "Go to the beginning of the message signature."
+  (interactive)
+  (goto-char (point-max))
+  (and (save-match-data
+        (re-search-backward (concat "^" post-signature-pattern
+                                    "[ \t\f]*$")
+                            nil t))))
+
+(defun post-delete-quoted-signatures ()
+  "Delete quoted signatures from buffer."
+  (interactive)
+  (goto-char (point-min))
+  (flush-lines (concat "^\\([ \t\f]*>[ \t\f>]*\\)"
+                      post-signature-pattern
+                      "[ \t\f]*\\(\n\\1.*\\)+")))
+
+(defun post-kill-signature ()
+  "Kill the signature from the buffer.
+Returns the point value for where the signature was or, if there isn't a
+signature, the point value of the end of the buffer"
+  (interactive)
+  (save-excursion
+    (goto-char (point-min))
+; The .=*+|#@!~$%&()_- is to compensate for people who put ASCII art on the
+; same line as the sigdashes, and the $ at the end prevents this from deleting
+; everything between mutt's standard forwarding lines.
+    (cond ((search-forward-regexp (concat "^" post-signature-pattern
+                                         "[ \t\f.=*+|#@!~$%&()_-]*$") nil t)
+          (beginning-of-line)
+          (kill-region (point) (point-max)))
+         (t
+          (goto-char (point-max))))
+    (point)))
+
+(defun post-delete-old-citations ()
+  "Delete citations more than one level deep from buffer."
+  (interactive)
+  (goto-char (point-min))
+  (flush-lines "^[ \t\f]*>[ \t\f]*>[ \t\f>]*"))
+
+;;; Functions for messing with the body
+
+(defun post-make-region-bold (start end)
+  "Apply mutt's nroff style bold to a region of text.
+Argument START start of region.
+Argument END end of region."
+  (interactive "r")
+  (while (< start end)
+    (goto-char start)
+    (insert (buffer-substring-no-properties start (1+ start)))
+    (insert (char-to-string 8))
+    (setq start (+ start 3))
+    (setq end   (+ end   2))))
+
+(defun post-make-region-underlined (start end)
+  "Apply mutt's nroff style underline to a region of text.
+Argument START start of region.
+Argument END end of region."
+  (interactive "r")
+  (while (< start end)
+    (goto-char start)
+    (insert "_")
+    (insert (char-to-string 8))
+    (setq start (+ start 3))
+    (setq end   (+ end   2))))
+
+(defun post-quote-region (beg end)
+  "Quote a region using the `post-quote-start' variable.
+Argument BEG Beginning of region to be quoted.
+Argument END End of region to be quoted."
+  (interactive "r")
+  (comment-region beg end))
+
+(defun post-unquote-region (beg end)
+  "Un-quote a region one level using the `post-quote-start' variable.
+Argument BEG Beginning of region to be quoted.
+Argument END End of region to be quoted."
+  (interactive "r")
+  (uncomment-region beg end))
+
+; From Dave Pearson, July 15, 2000
+(defun* split-quoted-paragraph (&optional (quote-string "> "))
+  "Split a quoted paragraph at point, keeping the quote."
+  (interactive)
+  (if (save-excursion
+        (beginning-of-line)
+        (looking-at (regexp-quote quote-string)))
+      (progn
+        (let ((spaces (- (point)
+                         (save-excursion
+                           (beginning-of-line)
+                           (point))
+                         (length quote-string))))
+          (save-excursion
+            (insert (format "\n\n%s%s" quote-string (make-string spaces ? ))))))
+    (error "Can't see a quoted paragraph here")))
+
+(defun post-random-signature ()
+  "Randomize the signature.
+Set it to whatever `post-random-signature-command' spits out followed by the
+content of `post-fixed-signature-source', if available, or a nasty reminder if
+it is not."
+  (interactive)
+  (save-excursion
+    (goto-char (post-kill-signature))
+    (insert "-- \n")
+    (shell-command post-random-signature-command t)
+    (goto-char (point-max))
+    (if (file-readable-p post-fixed-signature-source)
+       (insert-file-contents post-fixed-signature-source)
+      (insert "I really need a `post-fixed-signature-source'!\n"))))
+
+(defun post-el-random-signature ()
+  "Choose a random signature from `post-variable-signature-source'.
+the signatures in `post-variable-signature-source' must be separated by
+`post-signature-sep-regexp'."
+  (interactive)
+  (let ((sig nil))
+    (save-excursion
+      (set-buffer (generate-new-buffer "*Post-Select-Signature*"))
+      (insert-file post-variable-signature-source)
+      (beginning-of-buffer)
+      ;; we have 2 lists of marks since seperators are of arbitrary lenght
+      (let ((marks-st (list (point-min)))
+           (marks-end (list))
+           (count 0))          ;nth counts from zero and random is [0,N)
+       (while (search-forward-regexp post-signature-sep-regexp nil "a")
+         (setq marks-st (cons (match-end 0) marks-st)
+               marks-end (cons (match-beginning 0) marks-end)
+               count (1+ count)))
+       (setq marks-end (cons (point-max) marks-end))
+       (let ((r (random (1+ count))))
+         (setq sig (buffer-substring-no-properties
+                    (nth r marks-st) (nth r marks-end))))
+       (kill-buffer (current-buffer)))
+      (goto-char (post-kill-signature))
+      (insert-string "-- \n")
+      (insert sig)
+      (if (file-readable-p post-fixed-signature-source)
+         (insert-file-contents post-fixed-signature-source)
+       (insert "I really need a `post-fixed-signature-source'!\n")))))
+
+(defun post-select-signature-from-file ()
+  "*Interactively select a signature from `post-variable-signature-source'."
+  (interactive)
+  (setq post-select-signature-last-buffer (current-buffer))
+  (setq post-select-signature-last-point (point))
+  (pop-to-buffer "*Post-Select-Signature*")
+  (insert-file post-variable-signature-source)
+  (use-local-map post-select-signature-mode-map))
+
+(defun post-select-signature-select-sig-from-file ()
+ "*Chooses the signature the cursor is in from `post-variable-signature-source'."
+  (interactive)
+
+  ;; These 2 lines select whatever siglet the cursor is sitting in,
+  ;; making it nifty to C-s "word" then C-m (or whatever this is
+  ;; bound to).
+  (let ((sig-start (point))
+        (sig-end (point)))
+
+    (cond ((setq sig-start (search-backward-regexp post-signature-sep-regexp
+                                                  nil "a"))
+          (forward-line 1)
+          (setq sig-start (point))))
+
+    (if (search-forward-regexp post-signature-sep-regexp nil "a")
+       (setq sig-end (match-beginning 0))
+      (setq sig-end (point-max)))
+
+    (let ((sig (buffer-substring-no-properties sig-start sig-end)))
+      (switch-to-buffer post-select-signature-last-buffer)
+      (goto-char (post-kill-signature))
+      (insert-string "-- \n")
+      (insert sig))
+    (if (file-readable-p post-fixed-signature-source)
+       (insert-file-contents post-fixed-signature-source))
+    (post-select-signature-quit)))
+
+(defun post-select-signature-from-dir ()
+  "Select a new signature for an email/post in the current buffer."
+  (interactive)
+  (setq post-select-signature-last-buffer (current-buffer))
+  (setq post-select-signature-last-point (point))
+  (pop-to-buffer "*Post-Select-Signature*")
+  (list-directory (concat post-signature-directory
+                          post-signature-wildcard) t)
+  (pop-to-buffer "*Directory*")
+  (next-line 1)
+  (copy-to-buffer "*Post-Select-Signature*" (point) (point-max))
+  (kill-buffer "*Directory*")
+  (pop-to-buffer "*Post-Select-Signature*")
+  (use-local-map post-select-signature-mode-map)
+  (toggle-read-only t))
+
+(defun post-select-signature-select-sig-from-dir ()
+  "Set the signature in the calling buffer to the one under the cursor."
+  (interactive)
+  (let ((sig-start   nil)
+        (sig-to-load nil))
+    (end-of-line)
+    (search-backward " ")
+    (forward-char)
+    (setq sig-start (point))
+    (end-of-line)
+    (setq sig-to-load (buffer-substring-no-properties sig-start (point)))
+    (switch-to-buffer post-select-signature-last-buffer)
+    (goto-char (post-kill-signature))
+    (insert-string "-- \n")
+    (insert-file (concat post-signature-directory sig-to-load))
+    (message "Signature set to %s%s" post-signature-directory sig-to-load)
+    (post-select-signature-quit)))
+
+(defun post-select-signature-quit ()
+  "Kill the *Post-Select-Signature* frame."
+  (interactive)
+  (kill-buffer "*Post-Select-Signature*")
+  (switch-to-buffer post-select-signature-last-buffer)
+  (goto-char post-select-signature-last-point)
+  (delete-other-windows))
+
+;;; Non-interactive functions
+
+(defun post-ask-for-address-with-default (header)
+  "Prompt for an email address, showing default.
+Argument HEADER the header type."
+  (let ((default (if (= (length (post-get-header-value header)) 0)
+                     post-email-address
+                   (post-get-header-value header))))
+    (read-string (concat header ": ") default)))
+
+; From davep@davep.org.  RR hasn't tested it.
+(defun post-get-header-value (header)
+  "Get the value of a specific mail HEADER."
+  (save-excursion
+    (let ((value          "")
+          (start-of-value nil))
+      (setf (point) (point-min))
+      (when (post-find-header-line header)
+        (setq start-of-value (point))
+        (end-of-line)
+        (setq value (buffer-substring-no-properties start-of-value (point))))
+      value)))
+
+;;; From davep@davep.org.  RR hasn't tested it.
+(defun post-find-header-line (header)
+  "Find a HEADER line in the header."
+  (let ((old-point (point))
+        (end-of-header nil)
+        (found-point nil))
+    (setf (point) (point-min))
+    (search-forward-regexp "^$" nil t)
+    (setq end-of-header (point))
+    (setf (point) (point-min))
+    (cond ((search-forward-regexp (concat "^" header ": ") nil t)
+           (cond ((< (point) end-of-header)
+                  (setq found-point (point)))
+                 (t
+                  (setf (point) old-point))))
+          (t
+           (setf (point) old-point)))
+    found-point))
+
+;;; Function to make a backup buffer for viewing the original.
+(defun post-copy-original ()
+  "Make a copy of the `post-mode' buffer before any editing by the user.
+This way they can refer back to this buffer during a compose session."
+  (copy-to-buffer (get-buffer-create "*Original*")
+                 (point-min) (point-max)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; The Heart of Darkness
+;;;
+;;; The old post mode (i.e. Dave Pearson's) derived from mail-mode.  I
+;;; prefer deriving from text mode like mutt mode did. - RR
+(define-derived-mode post-mode text-mode "Post"
+  "Major mode for composing email or news with an external agent.
+To customize it, type \\[customize] and select [Applications] [Mail] [Post].
+When you finish editing this message, type \\[post-save-current-buffer-and-exit] to save and exit Emacs.
+
+\\{post-mode-map}"
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Neat things to do right off the bat.
+
+  (auto-fill-mode (if post-uses-fill-mode 1 0))
+
+  (if post-backup-original (post-copy-original))
+
+  ;; Make Emacs smarter about wrapping citations and paragraphs.
+  ;; We probably can't handle Supercited messages, though.
+  (make-local-variable 'paragraph-start)
+  (make-local-variable 'paragraph-separate)
+  (setq paragraph-start
+       "\\([ \t\n\f]+[^ \t\n\f>]\\|[ \t\f>]*$\\)"
+       paragraph-separate
+       "[ \t\f>]*$")
+
+  ;; XEmacs needs easy-menu-add, Emacs does not care
+  (easy-menu-add post-mode-menu)
+
+  ;; If headers were passed, activate the necessary commands.
+  (when (looking-at "^[-A-Za-z0-9]+:")
+    (header-mode 1))
+
+  ;; Our temporary file lives in /tmp. Yuck! Compensate appropriately.
+  (make-local-variable 'backup-inhibited)
+  (setq backup-inhibited t)
+
+  (if (boundp 'font-lock-defaults)
+      (make-local-variable 'font-lock-defaults))
+  (flet ((add-syntax-highlight (face regexps)
+           (set face face)
+           (nconc post-font-lock-keywords
+                  (loop for regexp in regexps
+                        collect (list regexp (list 0 face 't))))))
+;                       collect (list regexp `(,0 ',face))))))
+    (add-syntax-highlight 'post-emoticon-face post-emoticon-pattern)
+    (add-syntax-highlight 'post-bold-face   post-bold-pattern)
+    (add-syntax-highlight 'post-underline-face   post-underline-pattern)
+    (add-syntax-highlight 'post-url-face    post-url-pattern))
+  (setq font-lock-defaults
+       '(post-font-lock-keywords nil nil nil nil
+                                 (font-lock-syntactic-keywords
+                                  . post-font-lock-syntactic-keywords)
+                                 (font-lock-comment-face
+;                                 . 'post-signature-text-face)))
+                                  . post-signature-text-face)))
+
+  ;; Force pwd to home directory if so required.
+  (cond (post-force-pwd-to-home
+        (cd "~")))
+
+  ;; Kill quoted sig if so required.
+  (cond (post-kill-quoted-sig
+        (post-delete-quoted-signatures)
+         (not-modified)))
+
+  ;; Remap signature selection functions according to whether the
+  ;; signatures are stored in a file or directory.
+  (if post-signature-source-is-file
+      (progn
+       (defalias 'post-select-signature 'post-select-signature-from-file)
+       (defalias 'post-select-signature-select-sig
+         'post-select-signature-select-sig-from-file))
+    (progn
+      (defalias 'post-select-signature 'post-select-signature-from-dir)
+      (defalias 'post-select-signature-select-sig
+       'post-select-signature-select-sig-from-dir)))
+
+  ;; Define mutt/slrn specific key bindings.
+  (define-key (current-local-map) "\C-c\C-b"    'post-make-region-bold)
+  (define-key (current-local-map) "\C-c\C-u"    'post-make-region-underlined)
+  (define-key (current-local-map) "\C-c\C-q"    'post-quote-region)
+  (define-key (current-local-map) "\C-c\C-d\C-q" 'post-unquote-region)
+  (define-key (current-local-map) "\C-c\C-a"    'post-attach-file)
+  (define-key (current-local-map) "\C-c\C-p"    'post-set-return-receipt-to)
+
+  ;; Give the buffer a handy name.
+  (if post-rename-buffer
+      (setq post-buf (rename-buffer "*Composing*" t)))
+  ;; If this is a news posting, check the length of the References field.
+  (if (post-references-p)
+      (header-check-references))
+
+  ;; Define the quote signs as comments to make comment-region usable.
+  (make-local-variable 'comment-start)
+  (setq comment-start post-quote-start)
+
+  ;; Run any hooks.
+  (run-hooks 'post-mode-hook)
+
+  ;; Jump past header if so required.
+  (cond (post-jump-header
+         (post-goto-body)))
+
+  (unless (fboundp 'server-process-filter)
+    (message (substitute-command-keys
+     "Type \\[describe-mode] for help composing; \\[post-save-current-buffer-and-exit] when done."))))
+
+(defun post-references-p ()
+  "Is there a References header in this buffer?"
+  (save-excursion
+    (goto-char (point-min))
+    (looking-at "^References: ")))
+
+(defun post-body-says-attach ()
+  "Check if attach appears in the body."
+  (post-goto-body)
+  
+  ;; Aargh it's annoying that how-many returns a string,
+  ;; "13 occurences" instead of a number, 13.
+  (let ((total-attach (string-to-int (how-many post-attachment-regexp))))
+    ;; And this mess is just to catch the unlikely false alarm of
+    ;; "attach" being in the signature, but not in the body.
+    (if (> total-attach 0)
+       (progn (post-goto-signature)
+              (> total-attach (string-to-int (how-many
+                                              post-attachment-regexp)))))))
+
+(defun post-prompt-for-attachment ()
+  "Prompt for an attachment."
+   (if (y-or-n-p "Do you want to attach anything? ")
+       (let ((file (read-file-name "Attach file: " nil nil t nil))
+            (description (string-read "Description: ")))
+        (header-attach-file file description))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Post Header Mode
+
+(defvar header-mode nil)
+
+(defun header-mode (&optional arg)
+  "Commands for editing the header of an e-mail or news message.
+
+\\{header-mode-map}
+Optional argument ARG ."
+
+  (interactive "P")
+  (make-local-variable 'header-mode)
+  (setq header-mode
+       (if (null arg)
+           (not header-mode)
+         (> (prefix-numeric-value arg) 0)))
+  (setq post-has-attachment nil)
+
+  ;; XEmacs needs easy-menu-add, Emacs does not care
+  (easy-menu-add header-mode-menu)
+
+  (force-mode-line-update))
+
+(defvar header-mode-map (make-sparse-keymap)
+  "Keymap used for editing RFC822 header.")
+
+(defun header-position-on-value ()
+  "Go to the start of the value part of a header."
+  (beginning-of-line)
+  (skip-chars-forward "-A-Za-z0-9:")
+  ;; XXX - Should make sure we stay on line.
+  (forward-char)
+  (point))
+
+(defun header-goto-field (field)
+  "Go to FIELD of a header."
+  (let ((case-fold-search t))
+    (goto-char (point-min))
+    (save-match-data
+      (when (re-search-forward (concat "^\\($\\|" field ": \\)"))
+       (if (looking-at "^$")
+           (progn
+             (insert-string field ": \n")
+             (forward-char -1))
+         (header-position-on-value))))))
+
+(defmacro define-header-goto (name header)
+  "Define functions called NAME to go to HEADER."
+  `(defun ,name ()
+     ,(concat "Position the cursor on the " header ": header.")
+     (interactive)
+     (header-goto-field ,header)))
+
+(define-header-goto header-goto-to "To")
+(define-header-goto header-goto-cc "Cc")
+(define-header-goto header-goto-fcc "Fcc")
+(define-header-goto header-goto-summary "Summary")
+(define-header-goto header-goto-keywords "Keywords")
+(define-header-goto header-goto-subject "Subject")
+(define-header-goto header-goto-bcc "Bcc")
+(define-header-goto header-goto-reply-to "Reply-To")
+(define-header-goto header-goto-from "From")
+(define-header-goto header-goto-organization "Organization")
+
+(defun header-attach-file (file description)
+  "Attach a FILE to the current message (works with Mutt).
+Argument DESCRIPTION MIME description."
+  (interactive "fAttach file: \nsDescription: ")
+  (when (> (length file) 0)
+    (save-excursion
+      (save-match-data
+       (save-restriction
+         (widen)
+         (goto-char (point-min))
+         (search-forward-regexp "^$")
+         (insert-string (concat "Attach: " (file-truename file) " "
+                                description "\n"))
+         (message (concat "Attached '" file "'."))
+         (setq post-has-attachment t))))))
+
+(or (assq 'header-mode minor-mode-alist)
+    (setq minor-mode-alist
+         (cons '(header-mode " Header") minor-mode-alist)))
+
+(or (assq 'header-mode minor-mode-map-alist)
+    (setq minor-mode-map-alist
+         (cons (cons 'header-mode header-mode-map)
+               minor-mode-map-alist)))
+
+(defun header-set-return-receipt-to (address)
+  "Insert a Return-Receipt-To header into an email.
+Argument ADDRESS email address return receipts should be sent to."
+  (interactive (list (post-ask-for-address-with-default "Return-Receipt-To")))
+  (save-excursion
+    (header-set-value "Return-Receipt-To" address)))
+
+(defun post-news-posting-p ()
+  "Does the buffer look like a news posting?"
+  (save-excursion
+    (setf (point) (point-min))
+    (looking-at "^Newsgroups: ")))
+
+(defun header-set-followup-to (to)
+  "Set the Followup-To: header.
+Argument TO Where followups should go."
+  (interactive (list (header-ask-for-value "Followup-To"
+                                          (header-ask-for-value
+                                           "Newsgroups"))))
+  (cond ((post-news-posting-p)
+        (save-excursion
+          (header-set-value "Followup-To" to)))
+       (t
+        (error
+  "Followup-To is for Usenet.  Maybe you want Reply-To or Mail-Followup-To"))))
+
+(defun header-set-organization (org)
+  "Set the Organization: header.
+Argument ORG Should be SMERSH."
+  (interactive (list (header-ask-for-value "Organization")))
+  (save-excursion
+    (header-set-value "Organization" org)))
+
+(defun header-check-references ()
+  "Place the cursor at the start of the References: if they are too long."
+  (interactive)
+  (cond ((> (header-references-length) 500) ; 500 to be on the safe side.
+         (beep)                              ; Catch my attention.
+         (goto-char (point-min))
+         (search-forward-regexp "^References: " nil t))))
+
+(defun header-references-length (&optional show)
+  "Get (and optionally display) the length of the references header.
+Optional argument SHOW Whether or not to display the length."
+  (interactive)
+  (let* ((header "References")
+         (refs (header-get-value header))
+         (len (+ (length header) (length refs) 2)))
+    (if (or (interactive-p) show)
+        (message "References header is %d characters in length." len))
+    len))
+
+(defun header-delete-reference ()
+  "Delete the first reference in the references header."
+  (interactive)
+  (save-excursion
+    (let ((ref-location (header-goto-field "References")))
+      (cond (ref-location
+             (let ((ref-start (goto-char ref-location)))
+               (cond ((search-forward ">" nil t)
+                      (forward-char 1)
+                      (delete-region ref-start (point))
+                      (header-references-length t)))))))))
+
+;; Noninteractive functions.
+
+(defun header-ask-for-value (header &optional default)
+  "Ask for a HEADER value, defaulting to the current value if one is present.
+Optional argument DEFAULT ."
+  (let ((new-value (post-get-header-value header)))
+    (and (= (length new-value) 0)
+         default
+         (setq new-value default))
+    (read-string (concat header ": ") new-value)))
+
+(defun header-get-value (header)
+  "Get the value of a specific mail HEADER."
+  (save-excursion
+    (let ((value          "")
+          (start-of-value nil))
+      (goto-char (point-min))
+      (cond ((post-find-header-line header)
+             (setq start-of-value (point))
+             (end-of-line)
+             (setq value (buffer-substring-no-properties
+                         start-of-value (point)))))
+      value)))
+
+(defun header-set-value (header value)
+  "Set VALUE of a HEADER (replacing any existing value)."
+  (let ((kill-ring kill-ring))
+    (setf (point) (point-min))
+    (cond ((post-find-header-line header)
+          (beginning-of-line)
+          (kill-line)
+          (insert-string (concat header ": " value)))
+         (t
+          (header-append-value header value))))
+  (message "%s set to %s" header value))
+
+(defun header-append-value (header value)
+  "Add a HEADER and set it's VALUE (if header exists, will add multiple headers)."
+  (goto-char (point-min))
+  (search-forward-regexp "^$" nil t)
+  (insert-string (concat header ": " value "\n")))
+
+;;; Setup the mode map for the select-signature buffer.
+(if post-select-signature-mode-map nil
+  (setq post-select-signature-mode-map (make-sparse-keymap))
+  (define-key post-select-signature-mode-map "\C-m"
+    'post-select-signature-select-sig)
+  (define-key post-select-signature-mode-map " "
+    'post-select-signature-select-sig)
+  (define-key post-select-signature-mode-map "q" 'post-select-signature-quit)
+  (define-key post-select-signature-mode-map "\C-g"
+    'post-select-signature-quit))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Key Bindings
+
+(define-key post-mode-map "\C-c\C-c" 'post-save-current-buffer-and-exit)
+(define-key post-mode-map "\C-c\C-d\C-s" 'post-delete-quoted-signatures)
+(define-key post-mode-map "\C-c\C-d\C-c" 'post-delete-old-citations)
+(define-key post-mode-map "\C-c\C-t" 'post-goto-body)
+(define-key post-mode-map "\C-c\C-e" 'post-goto-signature)
+(define-key post-mode-map "\C-c\C-r" 'post-random-signature)
+(define-key post-mode-map "\C-c\C-b" 'post-make-region-bold)
+(define-key post-mode-map "\C-c\C-u" 'post-make-region-underlined)
+(define-key post-mode-map "\C-c\C-q" 'post-quote-region)
+(define-key post-mode-map "\C-c\C-d\C-q" 'post-unquote-region)
+(define-key post-mode-map "\C-c\C-s" 'post-select-signature)
+
+(define-key header-mode-map "\C-c\C-f\C-t" 'header-goto-to)
+(define-key header-mode-map "\C-c\C-f\C-c" 'header-goto-cc)
+(define-key header-mode-map "\C-c\C-f\C-w" 'header-goto-fcc)
+(define-key header-mode-map "\C-c\C-f\C-u" 'header-goto-summary)
+(define-key header-mode-map "\C-c\C-f\C-k" 'header-goto-keywords)
+(define-key header-mode-map "\C-c\C-f\C-s" 'header-goto-subject)
+(define-key header-mode-map "\C-c\C-f\C-b" 'header-goto-bcc)
+(define-key header-mode-map "\C-c\C-f\C-r" 'header-goto-reply-to)
+(define-key header-mode-map "\C-c\C-f\C-f" 'header-goto-from)
+(define-key header-mode-map "\C-c\C-f\C-o" 'header-goto-organization)
+(define-key header-mode-map "\C-c\C-ff"    'header-set-followup-to)
+(define-key header-mode-map "\C-c\C-a"     'header-attach-file)
+(define-key header-mode-map "\C-c\C-fd"    'header-delete-reference)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Menus
+
+(easy-menu-define
+ post-mode-menu post-mode-map "Post Message Composition Commands."
+ '("Post"
+   ["Delete quoted signatures" post-delete-quoted-signatures t]
+   ["Delete doubly quoted text" post-delete-old-citations t]
+   "----"
+   ["Go to body of message" post-goto-body t]
+   ["Go to signature of message" post-goto-signature t]
+   ["Get new random signature" post-random-signature t]
+   ["Select new signature" post-select-signature t]
+   "----"
+   ["Embolden region" post-make-region-bold t]
+   ["Underline region" post-make-region-underlined t]
+   "----"
+   ["Quote region" post-quote-region t]
+   ["Unquote region" post-unquote-region t]
+   "----"
+   ["Save message and return from Post" post-save-current-buffer-and-exit t]))
+
+(easy-menu-define
+ header-mode-menu header-mode-map "Header Editing Commands."
+ '("Header"
+   ["Attach File..." header-attach-file t]
+   "----"
+   ["Edit From Header" header-goto-from t]
+   ["Edit Subject Header" header-goto-subject t]
+   ["Edit To Header" header-goto-to t]
+   ["Edit Cc Header" header-goto-cc t]
+   ["Edit Bcc Header" header-goto-bcc t]
+   ["Edit Fcc Header" header-goto-fcc t]
+   ["Edit Reply-To Header" header-goto-reply-to t]
+   ["Edit Summary Header" header-goto-summary t]
+   ["Edit Keywords Header" header-goto-keywords t]
+   ["Edit Organization Header" header-goto-organization t]))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Finish Installing Post Mode
+
+(when post-insert-to-auto-mode-alist-on-load
+  (unless (assq post-mail-message auto-mode-alist)
+    (setq auto-mode-alist
+         (cons (cons post-mail-message 'post-mode)
+               auto-mode-alist)))
+  (unless (assq post-news-posting auto-mode-alist)
+    (setq auto-mode-alist
+         (cons (cons post-news-posting 'post-mode)
+               auto-mode-alist))))
+
+(provide 'post)
+
+;;; post.el ends here
diff --git a/emacs_el/psvn.el b/emacs_el/psvn.el
new file mode 100644 (file)
index 0000000..d057235
--- /dev/null
@@ -0,0 +1,2273 @@
+;;; psvn.el --- Subversion interface for emacs
+;; Copyright (C) 2002-2004 by Stefan Reichoer
+
+;; Author: Stefan Reichoer, <stefan@xsteve.at>
+;; $Id: psvn.el 10983 2004-09-15 18:38:26Z xsteve $
+
+;; psvn.el 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.
+
+;; psvn.el is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary
+
+;; psvn.el is tested with GNU Emacs 21.3 on windows, debian linux,
+;; freebsd5 with svn 1.05
+
+;; psvn.el is an interface for the revision control tool subversion
+;; (see http://subversion.tigris.org)
+;; psvn.el provides a similar interface for subversion as pcl-cvs for cvs.
+;; At the moment the following commands are implemented:
+;; M-x svn-status: run 'svn -status -v'
+;; and show the result in the *svn-status* buffer.  This buffer uses
+;; svn-status mode in which the following keys are defined:
+;; g     - svn-status-update:               run 'svn status -v'
+;; C-u g - svn-status-update:               run 'svn status -vu'
+;; =     - svn-status-show-svn-diff         run 'svn diff'
+;; l     - svn-status-show-svn-log          run 'svn log'
+;; i     - svn-status-info                  run 'svn info'
+;; r     - svn-status-revert                run 'svn revert'
+;; V     - svn-status-resolved              run 'svn resolved'
+;; U     - svn-status-update-cmd            run 'svn update'
+;; c     - svn-status-commit-file           run 'svn commit'
+;; a     - svn-status-add-file              run 'svn add --non-recursive'
+;; A     - svn-status-add-file-recursively  run 'svn add'
+;; +     - svn-status-make-directory        run 'svn mkdir'
+;; R     - svn-status-mv                    run 'svn mv'
+;; C-d   - svn-status-rm                    run 'svn rm'
+;; M-c   - svn-status-cleanup               run 'svn cleanup'
+;; b     - svn-status-blame                 run 'svn blame'
+;; RET   - svn-status-find-file-or-examine-directory
+;; ^     - svn-status-examine-parent
+;; ~     - svn-status-get-specific-revision
+;; E     - svn-status-ediff-with-revision
+;; s     - svn-status-show-process-buffer
+;; e     - svn-status-toggle-edit-cmd-flag
+;; ?     - svn-status-toggle-hide-unknown
+;; _     - svn-status-toggle-hide-unmodified
+;; m     - svn-status-set-user-mark
+;; u     - svn-status-unset-user-mark
+;; $     - svn-status-toggle-elide
+;; DEL   - svn-status-unset-user-mark-backwards
+;; * !   - svn-status-unset-all-usermarks
+;; * ?   - svn-status-mark-unknown
+;; * A   - svn-status-mark-added
+;; * M   - svn-status-mark-modified
+;; .     - svn-status-goto-root-or-return
+;; f     - svn-status-find-file
+;; o     - svn-status-find-file-other-window
+;; v     - svn-status-view-file-other-window
+;; I     - svn-status-parse-info
+;; P l   - svn-status-property-list
+;; P s   - svn-status-property-set
+;; P d   - svn-status-property-delete
+;; P e   - svn-status-property-edit-one-entry
+;; P i   - svn-status-property-ignore-file
+;; P I   - svn-status-property-ignore-file-extension
+;; P C-i - svn-status-property-edit-svn-ignore
+;; P k   - svn-status-property-set-keyword-list
+;; P y   - svn-status-property-set-eol-style
+;; h     - svn-status-use-history
+;; q     - svn-status-bury-buffer
+
+;; To use psvn.el put the following line in your .emacs:
+;; (require 'psvn)
+;; Start the svn interface with M-x svn-status
+
+;; The latest version of psvn.el can be found at:
+;;   http://www.xsteve.at/prg/emacs/psvn.el
+;; Or you can check it out from the subversion repository:
+;;   svn co http://svn.collab.net/repos/svn/trunk/contrib/client-side/psvn psvn
+
+;; TODO:
+;; * shortcut for svn propset svn:keywords "Date" psvn.el
+;; * docstrings for the functions
+;; * perhaps shortcuts for ranges, dates
+;; * when editing the command line - offer help from the svn client
+;; * finish svn-status-property-set
+;; * eventually use the customize interface
+;; * interactive svn-status should complete existing directories only;
+;;   unfortunately `read-directory-name' doesn't exist in Emacs 21.3
+;; * Add repository browser
+;; * Improve support for svn blame
+;; * Support for editing the log file entries, e.g.:
+;;   svn propedit --revprop -r9821 svn:log
+;; * Better logview mode (allow to show the changeset for a given entry)
+
+;; Overview over the implemented/not (yet) implemented svn sub-commands:
+;; * add                       implemented
+;; * blame                     implemented
+;; * cat                       implemented
+;; * checkout (co)
+;; * cleanup                   implemented
+;; * commit (ci)               implemented
+;; * copy (cp)
+;; * delete (del, remove, rm)  implemented
+;; * diff (di)                 implemented
+;; * export
+;; * help (?, h)
+;; * import
+;; * info                      implemented
+;; * list (ls)
+;; * log                       implemented
+;; * merge
+;; * mkdir                     implemented
+;; * move (mv, rename, ren)    implemented
+;; * propdel (pdel)            implemented
+;; * propedit (pedit, pe)      not needed
+;; * propget (pget, pg)        used
+;; * proplist (plist, pl)      implemented
+;; * propset (pset, ps)        used
+;; * resolved                  implemented
+;; * revert                    implemented
+;; * status (stat, st)         implemented
+;; * switch (sw)
+;; * update (up)               implemented
+
+;; For the not yet implemented commands you should use the command line
+;; svn client. If there are user requests for any missing commands I will
+;; probably implement them.
+
+;; Comments / suggestions and bug reports are welcome!
+
+;;; Code:
+
+;;; user setable variables
+(defvar svn-log-edit-file-name "++svn-log++" "*Name of a saved log file.")
+(defvar svn-status-hide-unknown nil "*Hide unknown files in *svn-status* buffer.")
+(defvar svn-status-hide-unmodified nil "*Hide unmodified files in *svn-status* buffer.")
+(defvar svn-status-directory-history nil "*List of visited svn working directories.")
+
+(defvar svn-status-unmark-files-after-list '(commit revert)
+  "*List of operations after which all user marks will be removed.
+Possible values are: commit, revert.")
+
+;;; default arguments to pass to svn commands
+(defvar svn-status-default-log-arguments ""
+  "*Arguments to pass to svn log.
+\(used in `svn-status-show-svn-log'; override these by giving prefixes\).")
+
+;;; hooks
+(defvar svn-log-edit-mode-hook nil "Hook run when entering `svn-log-edit-mode'.")
+
+(defvar svn-status-wash-control-M-in-process-buffers
+  (eq system-type 'windows-nt)
+  "*Remove any trailing ^M from the *svn-process* buffer.")
+
+;;; Customize group
+(defgroup psvn nil
+  "Subversion interface for Emacs."
+  :group 'tools)
+
+(defgroup psvn-faces nil
+  "psvn faces."
+  :group 'psvn)
+
+
+(eval-and-compile
+  (require 'cl)
+  (defconst svn-xemacsp (featurep 'xemacs))
+  (if svn-xemacsp
+      (require 'overlay)
+    (require 'overlay nil t)))
+
+;; Use the normally used mode for files ending in .~HEAD~, .~BASE~, ...
+(add-to-list 'auto-mode-alist '("\\.~?\\(HEAD\\|BASE\\|PREV\\)~?\\'" ignore t))
+
+;;; internal variables
+(defvar svn-process-cmd nil)
+(defvar svn-status-info nil)
+(defvar svn-status-base-info nil)
+(defvar svn-status-initial-window-configuration nil)
+(defvar svn-status-default-column 23)
+(defvar svn-status-default-revision-width 4)
+(defvar svn-status-default-author-width 9)
+(defvar svn-status-line-format " %c%c %4s %4s %-9s")
+(defvar svn-status-short-mod-flag-p t)
+(defvar svn-start-of-file-list-line-number 0)
+(defvar svn-status-files-to-commit nil)
+(defvar svn-status-pre-commit-window-configuration nil)
+(defvar svn-status-pre-propedit-window-configuration nil)
+(defvar svn-status-head-revision nil)
+(defvar svn-status-root-return-info nil)
+(defvar svn-status-property-edit-must-match-flag nil)
+(defvar svn-status-propedit-property-name nil)
+(defvar svn-status-propedit-file-list nil)
+(defvar svn-status-mode-line-process "")
+(defvar svn-status-mode-line-process-status "")
+(defvar svn-status-mode-line-process-edit-flag "")
+(defvar svn-status-edit-svn-command nil)
+(defvar svn-status-update-previous-process-output nil)
+(defvar svn-status-temp-dir
+  (or
+   (when (boundp 'temporary-file-directory) temporary-file-directory) ;emacs
+   (when (boundp 'temp-directory) temp-directory)                     ;xemacs
+   "/tmp/"))
+(defvar svn-temp-suffix (make-temp-name "."))
+(defvar svn-status-temp-file-to-remove nil)
+(defvar svn-status-temp-arg-file (concat svn-status-temp-dir "svn.arg" svn-temp-suffix))
+
+;;; faces
+(defface svn-status-marked-face
+  '((((type tty) (class color)) (:foreground "green" :weight light))
+    (((class color) (background light)) (:foreground "green3"))
+    (((class color) (background dark)) (:foreground "palegreen2"))
+    (t (:weight bold)))
+  "Face to highlight the mark for user marked files in svn status buffers."
+  :group 'psvn-faces)
+
+(defface svn-status-modified-external-face
+  '((((type tty) (class color)) (:foreground "magenta" :weight light))
+    (((class color) (background light)) (:foreground "magenta"))
+    (((class color) (background dark)) (:foreground "yellow"))
+    (t (:weight bold)))
+  "Face to highlight the phrase \"externally modified\" in *svn-status* buffers."
+  :group 'psvn-faces)
+
+;based on cvs-filename-face
+(defface svn-status-directory-face
+  '((((type tty) (class color)) (:foreground "lightblue" :weight light))
+    (((class color) (background light)) (:foreground "blue4"))
+    (((class color) (background dark)) (:foreground "lightskyblue1"))
+    (t (:weight bold)))
+  "Face for directories in svn status buffers.
+See `svn-status--line-info->directory-p' for what counts as a directory."
+  :group 'psvn-faces)
+
+;based on font-lock-comment-face
+(defface svn-status-filename-face
+  '((((class color) (background light)) (:foreground "chocolate"))
+    (((class color) (background dark)) (:foreground "beige")))
+  "Face for non-directories in svn status buffers.
+See `svn-status--line-info->directory-p' for what counts as a directory."
+  :group 'psvn-faces)
+
+(defvar svn-highlight t)
+;; stolen from PCL-CVS
+(defun svn-add-face (str face &optional keymap)
+  (when svn-highlight
+    ;; Do not use `list*'; cl.el might not have been loaded.  We could
+    ;; put (require 'cl) at the top but let's try to manage without.
+    (add-text-properties 0 (length str)
+                         `(face ,face
+                           ,@(when keymap
+                               `(mouse-face highlight
+                                 local-map ,keymap)))
+                         str))
+  str)
+
+(defun svn-status-maybe-add-face (condition text face)
+  "If CONDITION then add FACE to TEXT.
+Else return TEXT unchanged."
+  (if condition
+      (svn-add-face text face)
+    text))
+
+(defun svn-status-choose-face-to-add (condition text face1 face2)
+  "If CONDITION then add FACE1 to TEXT, else add FACE2 to TEXT."
+  (if condition
+      (svn-add-face text face1)
+    (svn-add-face text face2)))
+
+; compatibility
+; emacs 20
+(unless (fboundp 'point-at-eol) (defalias 'point-at-eol 'line-end-position))
+(unless (fboundp 'point-at-bol) (defalias 'point-at-bol 'line-beginning-position))
+(unless (functionp 'read-directory-name) (defalias 'read-directory-name 'read-file-name))
+
+(eval-when-compile
+  (if (not (fboundp 'gethash))
+      (require 'cl-macs)))
+(if (not (fboundp 'puthash))
+    (defalias 'puthash 'cl-puthash))
+
+(defvar svn-status-display-new-status-buffer nil)
+;;;###autoload
+(defun svn-status (dir &optional arg)
+  "Examine the status of Subversion working copy in directory DIR.
+If ARG then pass the -u argument to `svn status'."
+  (interactive (list (read-directory-name "SVN status directory: "
+                                          nil default-directory nil)))
+  (unless (file-directory-p dir)
+    (error "%s is not a directory" dir))
+  (if (not (file-exists-p (concat dir "/.svn/")))
+      (when (y-or-n-p
+             (concat dir
+                     " does not seem to be a Subversion working copy (no .svn directory).  "
+                     "Run dired instead? "))
+        (dired dir))
+    (setq dir (file-name-as-directory dir))
+    (setq svn-status-directory-history (delete dir svn-status-directory-history))
+    (add-to-list 'svn-status-directory-history dir)
+    (if (string= (buffer-name) "*svn-status*")
+        (setq svn-status-display-new-status-buffer nil)
+      (setq svn-status-display-new-status-buffer t)
+      ;;(message "psvn: Saving initial window configuration")
+      (setq svn-status-initial-window-configuration (current-window-configuration)))
+    (let* ((status-buf (get-buffer-create "*svn-status*"))
+           (proc-buf (get-buffer-create "*svn-process*")))
+      (save-excursion
+        (set-buffer status-buf)
+        (setq default-directory dir)
+        (set-buffer proc-buf)
+        (setq default-directory dir)
+        (if arg
+            (svn-run-svn t t 'status "status" "-vu")
+          (svn-run-svn t t 'status "status" "-v"))))))
+
+(defun svn-status-use-history ()
+  (interactive)
+  (let* ((hist svn-status-directory-history)
+         (dir (read-from-minibuffer "svn-status on directory: "
+                              (cadr svn-status-directory-history)
+                              nil nil 'hist)))
+    (when (file-directory-p dir)
+      (svn-status dir))))
+
+(defun svn-run-svn (run-asynchron clear-process-buffer cmdtype &rest arglist)
+  "Run svn with arguments ARGLIST.
+
+If RUN-ASYNCHRON is t then run svn asynchronously.
+
+If CLEAR-PROCESS-BUFFER is t then erase the contents of the
+*svn-process* buffer before commencing.
+
+CMDTYPE is a symbol such as 'mv, 'revert, or 'add, representing the
+command to run.
+
+ARGLIST is a list of arguments \(which must include the command name,
+for  example: '(\"revert\" \"file1\"\)"
+  (if (eq (process-status "svn") nil)
+      (progn
+        (when svn-status-edit-svn-command
+          (setq arglist (append arglist
+                                (split-string
+                                 (read-from-minibuffer
+                                  (format "svn %s %S " cmdtype arglist)))))
+          (when (eq svn-status-edit-svn-command t)
+            (svn-status-toggle-edit-cmd-flag t))
+          (message "svn-run-svn %s: %S" cmdtype arglist))
+        (let* ((proc-buf (get-buffer-create "*svn-process*"))
+               (svn-proc))
+          (when (listp (car arglist))
+            (setq arglist (car arglist)))
+          (save-excursion
+            (set-buffer proc-buf)
+            (setq buffer-read-only nil)
+            (fundamental-mode)
+            (if clear-process-buffer
+                (delete-region (point-min) (point-max))
+              (goto-char (point-max)))
+            (setq svn-process-cmd cmdtype)
+            (setq svn-status-mode-line-process-status (format " running %s" cmdtype))
+            (svn-status-update-mode-line)
+            (sit-for 0.1)
+            (if run-asynchron
+                (progn
+                  (setq svn-proc (apply 'start-process "svn" proc-buf "svn" arglist))
+                  (set-process-sentinel svn-proc 'svn-process-sentinel))
+              ;;(message "running synchron: svn %S" arglist)
+              (apply 'call-process "svn" nil proc-buf nil arglist)
+              (setq svn-status-mode-line-process-status "")
+              (svn-status-update-mode-line)))))
+    (error "You can only run one svn process at once!")))
+
+(defun svn-process-sentinel (process event)
+  ;;(princ (format "Process: %s had the event `%s'" process event)))
+  ;;(save-excursion
+  (let ((act-buf (current-buffer)))
+    (set-buffer (process-buffer process))
+    (setq svn-status-mode-line-process-status "")
+    (svn-status-update-mode-line)
+    (cond ((string= event "finished\n")
+           (cond ((eq svn-process-cmd 'status)
+                  ;;(message "svn status finished")
+                  (if (eq system-type 'windows-nt)
+                      ;; convert path separator as UNIX style
+                      (save-excursion
+                        (goto-char (point-min))
+                        (while (search-forward "\\" nil t)
+                          (replace-match "/"))))
+                  (svn-parse-status-result)
+                  (set-buffer act-buf)
+                  (svn-status-update-buffer)
+                  (when svn-status-update-previous-process-output
+                    (set-buffer (process-buffer process))
+                    (delete-region (point-min) (point-max))
+                    (insert "Output from svn command:\n")
+                    (insert svn-status-update-previous-process-output)
+                    (goto-char (point-min))
+                    (setq svn-status-update-previous-process-output nil))
+                  (when svn-status-display-new-status-buffer
+                    (set-window-configuration svn-status-initial-window-configuration)
+                    (switch-to-buffer "*svn-status*")))
+                 ((eq svn-process-cmd 'log)
+                  (svn-status-show-process-buffer-internal t)
+                  (pop-to-buffer "*svn-process*")
+                  (switch-to-buffer (get-buffer-create "*svn-log*"))
+                  (let ((buffer-read-only nil))
+                    (delete-region (point-min) (point-max))
+                    (insert-buffer-substring "*svn-process*"))
+                  (svn-log-view-mode)
+                  (goto-char (point-min))
+                  (forward-line 3)
+                  (font-lock-fontify-buffer)
+                  (message "svn log finished"))
+                 ((eq svn-process-cmd 'info)
+                  (svn-status-show-process-buffer-internal t)
+                  (message "svn info finished"))
+                 ((eq svn-process-cmd 'parse-info)
+                  (svn-status-parse-info-result))
+                 ((eq svn-process-cmd 'blame)
+                  (svn-status-show-process-buffer-internal t)
+                  (message "svn blame finished"))
+                 ((eq svn-process-cmd 'commit)
+                  (svn-status-remove-temp-file-maybe)
+                  (svn-status-show-process-buffer-internal t)
+                  (when (member 'commit svn-status-unmark-files-after-list)
+                    (svn-status-unset-all-usermarks))
+                  (svn-status-update)
+                  (message "svn commit finished"))
+                 ((eq svn-process-cmd 'update)
+                  (svn-status-show-process-buffer-internal t)
+                  (svn-status-update)
+                  (message "svn update finished"))
+                 ((eq svn-process-cmd 'add)
+                  (svn-status-update)
+                  (message "svn add finished"))
+                 ((eq svn-process-cmd 'mkdir)
+                  (svn-status-update)
+                  (message "svn mkdir finished"))
+                 ((eq svn-process-cmd 'revert)
+                  (when (member 'revert svn-status-unmark-files-after-list)
+                    (svn-status-unset-all-usermarks))
+                  (svn-status-update)
+                  (message "svn revert finished"))
+                 ((eq svn-process-cmd 'resolved)
+                  (svn-status-update)
+                  (message "svn resolved finished"))
+                 ((eq svn-process-cmd 'mv)
+                  (svn-status-update)
+                  (message "svn mv finished"))
+                 ((eq svn-process-cmd 'rm)
+                  (svn-status-update)
+                  (message "svn rm finished"))
+                 ((eq svn-process-cmd 'cleanup)
+                  (message "svn cleanup finished"))
+                 ((eq svn-process-cmd 'proplist)
+                  (svn-status-show-process-buffer-internal t)
+                  (message "svn proplist finished"))
+                 ((eq svn-process-cmd 'proplist-parse)
+                  (svn-status-property-parse-property-names))
+                 ((eq svn-process-cmd 'propset)
+                  (svn-status-remove-temp-file-maybe)
+                  (svn-status-update))
+                 ((eq svn-process-cmd 'propdel)
+                  (svn-status-update))))
+          ((string= event "killed\n")
+           (message "svn process killed"))
+          ((string-match "exited abnormally" event)
+           (while (accept-process-output process 0 100))
+           ;; find last error message and show it.
+           (goto-char (point-max))
+           (message "svn failed: %s"
+                    (if (re-search-backward "^svn: \\(.*\\)" nil t)
+                        (match-string 1)
+                      event)))
+          (t
+           (message "svn process had unknown event: %s" event))
+          (svn-status-show-process-buffer-internal t))))
+
+(defun svn-parse-rev-num (str)
+  (if (and str (stringp str)
+           (save-match-data (string-match "^[0-9]+" str)))
+      (string-to-number str)
+    -1))
+
+
+(defun svn-parse-status-result ()
+    "Parse the *svn-process* buffer.
+The results are used to build the `svn-status-info' variable."
+  (setq svn-status-head-revision nil)
+  (save-excursion
+    (let ((old-ui-information (svn-status-ui-information-hash-table))
+          (line-string)
+          (user-mark)
+          (svn-marks)
+          (svn-file-mark)
+          (svn-property-mark)
+          (svn-update-mark)
+          (local-rev)
+          (last-change-rev)
+          (author)
+          (path)
+          (user-elide nil)
+          (ui-status '(nil nil)) ; contains (user-mark user-elide)
+          (revision-width svn-status-default-revision-width)
+          (author-width svn-status-default-author-width))
+      (set-buffer "*svn-process*")
+      (setq svn-status-info nil)
+      (goto-char (point-min))
+      (while (< (point) (point-max))
+        (cond
+         ((= (point-at-eol) (point-at-bol)) ;skip blank lines
+          nil)
+         ((looking-at "Status against revision:[ ]+\\([0-9]+\\)")
+          ;; the above message appears for the main listing plus once for each svn:externals entry
+          (unless svn-status-head-revision
+            (setq svn-status-head-revision (match-string 1))))
+         ((looking-at "Performing status on external item at '\(.*\)'")
+          ;; The *next* line has info about the directory named in svn:externals
+          ;; we should parse it, and merge the info with what we have already know
+          ;; but for now just ignore the line completely
+          (forward-line)
+          )
+         (t
+          (setq svn-marks (buffer-substring (point) (+ (point) 8))
+                svn-file-mark (elt svn-marks 0)              ; 1st column
+                svn-property-mark (elt svn-marks 1)          ; 2nd column
+                ;;svn-locked-mark (elt svn-marks 2)            ; 3rd column
+                ;;svn-added-with-history-mark (elt svn-marks 3); 4th column
+                ;;svn-switched-mark (elt svn-marks 4)          ; 5th column
+                svn-update-mark (elt svn-marks 7))           ; 8th column
+
+          (when (eq svn-property-mark ?\ ) (setq svn-property-mark nil))
+          (when (eq svn-update-mark ?\ ) (setq svn-update-mark nil))
+          (forward-char 8)
+          (skip-chars-forward " ")
+          (cond
+           ((looking-at "\\([-?]\\|[0-9]+\\) +\\([-?]\\|[0-9]+\\) +\\([^ ]+\\) *\\(.+\\)")
+            (setq local-rev (svn-parse-rev-num (match-string 1))
+                  last-change-rev (svn-parse-rev-num (match-string 2))
+                  author (match-string 3)
+                  path (match-string 4)))
+           ((looking-at "\\(.*\\)")
+            (setq path (match-string 1)
+                  local-rev -1
+                  last-change-rev -1
+                  author (if (eq svn-file-mark 88) "" "?"))) ;clear author of svn:externals dirs
+           (t
+            (error "Unknown status line format")))
+          (unless path (setq path "."))
+          (setq ui-status (or (gethash path old-ui-information) (list user-mark user-elide)))
+          (setq svn-status-info (cons (list ui-status
+                                            svn-file-mark
+                                            svn-property-mark
+                                            path
+                                            local-rev
+                                            last-change-rev
+                                            author
+                                            svn-update-mark)
+                                      svn-status-info))
+          (setq revision-width (max revision-width
+                                                                        (length (number-to-string local-rev))
+                                                                        (length (number-to-string last-change-rev))))
+          (setq author-width (max author-width (length author)))))
+                (forward-line 1))
+      ;; With subversion 0.29.0 and above, `svn -u st' returns files in
+      ;; a random order (especially if we have a mixed revision wc)
+      (setq svn-status-default-column
+            (+ 6 revision-width revision-width author-width
+               (if svn-status-short-mod-flag-p 3 0)))
+      (setq svn-status-line-format (format " %%c%%c %%%ds %%%ds %%-%ds"
+                                           revision-width
+                                           revision-width
+                                           author-width))
+      (setq svn-status-info (sort svn-status-info 'svn-status-sort-predicate)))))
+
+;;(string-lessp "." "%") => nil
+;(svn-status-sort-predicate '(t t t ".") '(t t t "%")) => t
+(defun svn-status-sort-predicate (a b)
+  "Return t if A should appear before B in the *svn-status* buffer.
+A and B must be line-info's."
+  (string-lessp (concat (svn-status-line-info->full-path a) "/")
+                (concat (svn-status-line-info->full-path b) "/")))
+
+(defun svn-status-remove-temp-file-maybe ()
+  "Remove any (no longer required) temporary files created by psvn.el."
+  (when svn-status-temp-file-to-remove
+    (when (file-exists-p svn-status-temp-file-to-remove)
+      (delete-file svn-status-temp-file-to-remove))
+    (when (file-exists-p svn-status-temp-arg-file)
+      (delete-file svn-status-temp-arg-file))
+    (setq svn-status-temp-file-to-remove nil)))
+
+(defun svn-status-remove-control-M ()
+  "Remove ^M at end of line in the whole buffer."
+  (interactive)
+  (let ((buffer-read-only nil))
+    (save-match-data
+      (save-excursion
+        (goto-char (point-min))
+        (while (re-search-forward "\r$" (point-max) t)
+          (replace-match "" nil nil))))))
+
+(condition-case nil
+    ;;(easy-menu-add-item nil '("tools") ["SVN Status" svn-status t] "PCL-CVS")
+    (easy-menu-add-item nil '("tools") ["SVN Status" svn-status t])
+  (error (message "psvn: could not install menu")))
+
+(defvar svn-status-mode-map () "Keymap used in `svn-status-mode' buffers.")
+(defvar svn-status-mode-property-map ()
+  "Subkeymap used in `svn-status-mode' for property commands.")
+
+(when (not svn-status-mode-map)
+  (setq svn-status-mode-map (make-sparse-keymap))
+  (suppress-keymap svn-status-mode-map)
+  ;; Don't use (kbd "<return>"); it's unreachable with GNU Emacs 21.3 on a TTY.
+  (define-key svn-status-mode-map (kbd "RET") 'svn-status-find-file-or-examine-directory)
+  (define-key svn-status-mode-map (kbd "^") 'svn-status-examine-parent)
+  (define-key svn-status-mode-map (kbd "s") 'svn-status-show-process-buffer)
+  (define-key svn-status-mode-map (kbd "f") 'svn-status-find-files)
+  (define-key svn-status-mode-map (kbd "o") 'svn-status-find-file-other-window)
+  (define-key svn-status-mode-map (kbd "v") 'svn-status-view-file-other-window)
+  (define-key svn-status-mode-map (kbd "e") 'svn-status-toggle-edit-cmd-flag)
+  (define-key svn-status-mode-map (kbd "g") 'svn-status-update)
+  (define-key svn-status-mode-map (kbd "q") 'svn-status-bury-buffer)
+  (define-key svn-status-mode-map (kbd "h") 'svn-status-use-history)
+  (define-key svn-status-mode-map (kbd "m") 'svn-status-set-user-mark)
+  (define-key svn-status-mode-map (kbd "u") 'svn-status-unset-user-mark)
+  ;; This matches a binding of `dired-unmark-all-files' in `dired-mode-map'
+  ;; of both GNU Emacs and XEmacs.  It seems unreachable with XEmacs on
+  ;; TTY, but if that's a problem then its Dired needs fixing too.
+  ;; Or you could just use "*!".
+  (define-key svn-status-mode-map "\M-\C-?" 'svn-status-unset-all-usermarks)
+  ;; The key that normally deletes characters backwards should here
+  ;; instead unmark files backwards.  In GNU Emacs, that would be (kbd
+  ;; "DEL") aka [?\177], but XEmacs treats those as [(delete)] and
+  ;; would bind a key that normally deletes forwards.  [(backspace)]
+  ;; is unreachable with GNU Emacs on a tty.  Try to recognize the
+  ;; dialect and act accordingly.
+  ;;
+  ;; XEmacs has a `delete-forward-p' function that checks the
+  ;; `delete-key-deletes-forward' option.  We don't use those, for two
+  ;; reasons: psvn.el may be loaded before user customizations, and
+  ;; XEmacs allows simultaneous connections to multiple devices with
+  ;; different keyboards.
+  (define-key svn-status-mode-map
+              (if (member (kbd "DEL") '([(delete)] [delete]))
+                  [(backspace)]         ; XEmacs
+                (kbd "DEL"))            ; GNU Emacs
+              'svn-status-unset-user-mark-backwards)
+  (define-key svn-status-mode-map (kbd "$") 'svn-status-toggle-elide)
+  (define-key svn-status-mode-map (kbd ".") 'svn-status-goto-root-or-return)
+  (define-key svn-status-mode-map (kbd "I") 'svn-status-parse-info)
+  (define-key svn-status-mode-map (kbd "?") 'svn-status-toggle-hide-unknown)
+  (define-key svn-status-mode-map (kbd "_") 'svn-status-toggle-hide-unmodified)
+  (define-key svn-status-mode-map (kbd "a") 'svn-status-add-file)
+  (define-key svn-status-mode-map (kbd "A") 'svn-status-add-file-recursively)
+  (define-key svn-status-mode-map (kbd "+") 'svn-status-make-directory)
+  (define-key svn-status-mode-map (kbd "R") 'svn-status-mv)
+  (define-key svn-status-mode-map (kbd "D") 'svn-status-rm)
+  (define-key svn-status-mode-map (kbd "c") 'svn-status-commit-file)
+  (define-key svn-status-mode-map (kbd "M-c") 'svn-status-cleanup)
+  (define-key svn-status-mode-map (kbd "U") 'svn-status-update-cmd)
+  (define-key svn-status-mode-map (kbd "r") 'svn-status-revert)
+  (define-key svn-status-mode-map (kbd "l") 'svn-status-show-svn-log)
+  (define-key svn-status-mode-map (kbd "i") 'svn-status-info)
+  (define-key svn-status-mode-map (kbd "b") 'svn-status-blame)
+  (define-key svn-status-mode-map (kbd "=") 'svn-status-show-svn-diff)
+  ;; [(control ?=)] is unreachable on TTY, but you can use "*u" instead.
+  ;; (Is the "u" mnemonic for something?)
+  (define-key svn-status-mode-map (kbd "C-=") 'svn-status-show-svn-diff-for-marked-files)
+  (define-key svn-status-mode-map (kbd "~") 'svn-status-get-specific-revision)
+  (define-key svn-status-mode-map (kbd "E") 'svn-status-ediff-with-revision)
+  (define-key svn-status-mode-map (kbd "C-n") 'svn-status-next-line)
+  (define-key svn-status-mode-map (kbd "C-p") 'svn-status-previous-line)
+  (define-key svn-status-mode-map (kbd "<down>") 'svn-status-next-line)
+  (define-key svn-status-mode-map (kbd "<up>") 'svn-status-previous-line)
+  (setq svn-status-mode-mark-map (make-sparse-keymap))
+  (define-key svn-status-mode-map (kbd "*") svn-status-mode-mark-map)
+  (define-key svn-status-mode-mark-map (kbd "!") 'svn-status-unset-all-usermarks)
+  (define-key svn-status-mode-mark-map (kbd "?") 'svn-status-mark-unknown)
+  (define-key svn-status-mode-mark-map (kbd "A") 'svn-status-mark-added)
+  (define-key svn-status-mode-mark-map (kbd "M") 'svn-status-mark-modified)
+  (define-key svn-status-mode-mark-map (kbd "V") 'svn-status-resolved)
+  (define-key svn-status-mode-mark-map (kbd "u") 'svn-status-show-svn-diff-for-marked-files))
+(when (not svn-status-mode-property-map)
+  (setq svn-status-mode-property-map (make-sparse-keymap))
+  (define-key svn-status-mode-property-map (kbd "l") 'svn-status-property-list)
+  (define-key svn-status-mode-property-map (kbd "s") 'svn-status-property-set)
+  (define-key svn-status-mode-property-map (kbd "d") 'svn-status-property-delete)
+  (define-key svn-status-mode-property-map (kbd "e") 'svn-status-property-edit-one-entry)
+  (define-key svn-status-mode-property-map (kbd "i") 'svn-status-property-ignore-file)
+  (define-key svn-status-mode-property-map (kbd "I") 'svn-status-property-ignore-file-extension)
+  ;; XEmacs 21.4.15 on TTY (vt420) converts `C-i' to `TAB',
+  ;; which [(control ?i)] won't match.  Handle it separately.
+  ;; On GNU Emacs, the following two forms bind the same key,
+  ;; reducing clutter in `where-is'.
+  (define-key svn-status-mode-property-map [(control ?i)] 'svn-status-property-edit-svn-ignore)
+  (define-key svn-status-mode-property-map (kbd "TAB") 'svn-status-property-edit-svn-ignore)
+  (define-key svn-status-mode-property-map (kbd "k") 'svn-status-property-set-keyword-list)
+  (define-key svn-status-mode-property-map (kbd "y") 'svn-status-property-set-eol-style)
+  (define-key svn-status-mode-property-map (kbd "p") 'svn-status-property-parse)
+  ;; TODO: Why is `svn-status-select-line' in `svn-status-mode-property-map'?
+  (define-key svn-status-mode-property-map (kbd "RET") 'svn-status-select-line)
+  (define-key svn-status-mode-map (kbd "P") svn-status-mode-property-map))
+
+
+(easy-menu-define svn-status-mode-menu svn-status-mode-map
+  "'svn-status-mode' menu"
+  '("SVN"
+    ["svn status" svn-status-update t]
+    ["svn update" svn-status-update-cmd t]
+    ["svn commit" svn-status-commit-file t]
+    ["svn log" svn-status-show-svn-log t]
+    ["svn info" svn-status-info t]
+    ["svn blame" svn-status-blame t]
+    ("Diff"
+     ["svn diff current file" svn-status-show-svn-diff t]
+     ["svn diff marked files" svn-status-show-svn-diff-for-marked-files t]
+     ["svn ediff current file" svn-status-ediff-with-revision t]
+     )
+    ["svn cat ..." svn-status-get-specific-revision t]
+    ["svn add" svn-status-add-file t]
+    ["svn mkdir..." svn-status-make-directory t]
+    ["svn mv..." svn-status-mv t]
+    ["svn rm..." svn-status-rm t]
+    ["Up Directory" svn-status-examine-parent t]
+    ["Elide Directory" svn-status-toggle-elide t]
+    ["svn revert" svn-status-revert t]
+    ["svn resolved" svn-status-resolved t]
+    ["svn cleanup" svn-status-cleanup t]
+    ["Show Process Buffer" svn-status-show-process-buffer t]
+    ("Property"
+     ["svn proplist" svn-status-property-list t]
+     ["Set Multiple Properties..." svn-status-property-set t]
+     ["Edit One Property..." svn-status-property-edit-one-entry t]
+     ["svn propdel..." svn-status-property-delete t]
+     "---"
+     ["svn:ignore File..." svn-status-property-ignore-file t]
+     ["svn:ignore File Extension..." svn-status-property-ignore-file-extension t]
+     ["Edit svn:ignore Property" svn-status-property-edit-svn-ignore t]
+     "---"
+     ["Set svn:keywords List" svn-status-property-set-keyword-list t]
+     ["Set svn:eol-style" svn-status-property-set-eol-style t]
+     )
+    "---"
+    ["Edit Next SVN Cmd Line" svn-status-toggle-edit-cmd-flag t]
+    ["Work Directory History..." svn-status-use-history t]
+    ["Mark" svn-status-set-user-mark t]
+    ["Unmark" svn-status-unset-user-mark t]
+    ("Mark / Unmark"
+     ["Unmark all" svn-status-unset-all-usermarks t]
+     ["Mark/Unmark unknown" svn-status-mark-unknown t]
+     ["Mark/Unmark added" svn-status-mark-added t]
+     ["Mark/Unmark modified" svn-status-mark-modified t]
+     )
+    ["Hide Unknown" svn-status-toggle-hide-unknown
+     :style toggle :selected svn-status-hide-unknown]
+    ["Hide Unmodified" svn-status-toggle-hide-unmodified
+     :style toggle :selected svn-status-hide-unmodified]
+    ))
+
+(defun svn-status-mode ()
+  "Major mode used by  psvn.el to process the output of \"svn status\".
+
+psvn.el is an interface for the revision control tool subversion
+\(see http://subversion.tigris.org).
+psvn.el provides a similar interface for subversion as pcl-cvs does for cvs.
+At the moment the following commands are implemented:
+  M-x svn-status: run 'svn -status -v'
+  and show the result in the *svn-status* buffer, this buffer uses the
+  svn-status mode. In this mode the following keys are defined:
+\\{svn-status-mode-map}"
+  (interactive)
+  (kill-all-local-variables)
+
+  (use-local-map svn-status-mode-map)
+  (easy-menu-add svn-status-mode-menu)
+
+  (setq major-mode 'svn-status-mode)
+  (setq mode-name "svn-status")
+  (setq mode-line-process 'svn-status-mode-line-process)
+  (let ((view-read-only nil))
+    (toggle-read-only 1)))
+
+(defun svn-status-update-mode-line ()
+  (setq svn-status-mode-line-process
+        (concat svn-status-mode-line-process-edit-flag svn-status-mode-line-process-status))
+  (force-mode-line-update))
+
+(defun svn-status-bury-buffer (arg)
+  "Bury the *svn-status* buffer.
+When called with a prefix argument, switch back to the window configuration that was
+in use before `svn-status' was called."
+  (interactive "P")
+  (cond (arg
+         (when svn-status-initial-window-configuration
+           (set-window-configuration svn-status-initial-window-configuration)))
+        (t
+         (let ((bl '("*svn-log-edit*" "*svn-property-edit*" "*svn-process*")))
+           (while bl
+             (when (get-buffer (car bl))
+               (bury-buffer (car bl)))
+             (setq bl (cdr bl)))
+           (when (string= (buffer-name) "*svn-status*")
+             (bury-buffer))))))
+
+(defun svn-status-find-files ()
+  "Open selected file(s) for editing.
+See `svn-status-marked-files' for what counts as selected."
+  (interactive)
+  (let ((fnames (mapcar 'svn-status-line-info->full-path (svn-status-marked-files))))
+    (mapc 'find-file fnames)))
+
+
+(defun svn-status-find-file-other-window ()
+  "Open the file in the other window for editing."
+  (interactive)
+  (find-file-other-window (svn-status-line-info->filename
+                           (svn-status-get-line-information))))
+
+(defun svn-status-view-file-other-window ()
+  "Open the file in the other window for viewing."
+  (interactive)
+  (view-file-other-window (svn-status-line-info->filename
+                           (svn-status-get-line-information))))
+
+(defun svn-status-find-file-or-examine-directory ()
+  "If point is on a directory, run `svn-status' on that directory.
+Otherwise run `find-file'."
+  (interactive)
+  (let ((line-info (svn-status-get-line-information)))
+    (if (svn-status-line-info->directory-p line-info)
+        (svn-status (svn-status-line-info->full-path line-info))
+      (find-file (svn-status-line-info->filename line-info)))))
+
+(defun svn-status-examine-parent ()
+  "Run `svn-status' on the parent of the current directory."
+  (interactive)
+  (svn-status (expand-file-name "../")))
+
+(defun svn-status-line-info->ui-status (line-info) (nth 0 line-info))
+
+(defun svn-status-line-info->has-usermark (line-info) (nth 0 (nth 0 line-info)))
+(defun svn-status-line-info->user-elide (line-info) (nth 1 (nth 0 line-info)))
+
+(defun svn-status-line-info->filemark (line-info) (nth 1 line-info))
+(defun svn-status-line-info->propmark (line-info) (nth 2 line-info))
+(defun svn-status-line-info->filename (line-info) (nth 3 line-info))
+(defun svn-status-line-info->filename-nondirectory (line-info)
+  (file-name-nondirectory (svn-status-line-info->filename line-info)))
+(defun svn-status-line-info->localrev (line-info)
+  (if (>= (nth 4 line-info) 0)
+      (nth 4 line-info)
+    nil))
+(defun svn-status-line-info->lastchangerev (line-info)
+  "Return the last revision in which LINE-INFO was modified."
+  (if (>= (nth 5 line-info) 0)
+      (nth 5 line-info)
+    nil))
+(defun svn-status-line-info->author (line-info) (nth 6 line-info))
+(defun svn-status-line-info->modified-external (line-info) (nth 7 line-info))
+
+(defun svn-status-line-info->is-visiblep (line-info)
+  (not (or (svn-status-line-info->hide-because-unknown line-info)
+           (svn-status-line-info->hide-because-unmodified line-info)
+           (svn-status-line-info->hide-because-user-elide line-info))))
+
+(defun svn-status-line-info->hide-because-unknown (line-info)
+  (and svn-status-hide-unknown
+       (eq (svn-status-line-info->filemark line-info) ??)))
+
+(defun svn-status-line-info->hide-because-unmodified (line-info)
+  ;;(message " %S %S %S %S - %s" svn-status-hide-unmodified (svn-status-line-info->propmark line-info) ?_
+  ;;         (svn-status-line-info->filemark line-info) (svn-status-line-info->filename line-info))
+  (and svn-status-hide-unmodified
+       (and (or (eq (svn-status-line-info->filemark line-info) ?_)
+                (eq (svn-status-line-info->filemark line-info) ? ))
+            (or (eq (svn-status-line-info->propmark line-info) ?_)
+                (eq (svn-status-line-info->propmark line-info) ? )
+                (eq (svn-status-line-info->propmark line-info) nil)))))
+
+(defun svn-status-line-info->hide-because-user-elide (line-info)
+  (eq (svn-status-line-info->user-elide line-info) t))
+
+(defun svn-status-line-info->show-user-elide-continuation (line-info)
+  (eq (svn-status-line-info->user-elide line-info) 'directory))
+
+;; modify the line-info
+(defun svn-status-line-info->set-filemark (line-info value)
+  (setcar (nthcdr 1 line-info) value))
+
+(defun svn-status-toggle-elide ()
+  (interactive)
+  (let ((st-info svn-status-info)
+        (fname)
+        (test (svn-status-line-info->filename (svn-status-get-line-information)))
+        (len-test)
+        (len-fname)
+        (new-elide-mark t)
+        (elide-mark))
+    (when (string= test ".")
+      (setq test ""))
+    (setq len-test (length test))
+    (while st-info
+      (setq fname (svn-status-line-info->filename (car st-info)))
+      (setq len-fname (length fname))
+      (when (and (>= len-fname len-test)
+                 (string= (substring fname 0 len-test) test))
+        ;;(message "elide: %s %s" fname (svn-status-line-info->user-elide (car st-info)))
+        (setq elide-mark new-elide-mark)
+        (when (or (string= fname ".")
+                  (and (= len-fname len-test) (svn-status-line-info->directory-p (car st-info))))
+          (message "Elide directory %s and all its files." fname)
+          (setq new-elide-mark (not (svn-status-line-info->user-elide (car st-info))))
+          (setq elide-mark (if new-elide-mark 'directory nil)))
+        (setcar (nthcdr 1 (svn-status-line-info->ui-status (car st-info))) elide-mark))
+      (setq st-info (cdr st-info))))
+  (svn-status-update-buffer))
+
+
+(defun svn-status-line-info->directory-p (line-info)
+  "Return t if LINE-INFO refers to a directory, nil otherwise.
+Symbolic links to directories count as directories (see `file-directory-p')."
+  (file-directory-p (svn-status-line-info->filename line-info)))
+
+(defun svn-status-line-info->full-path (line-info)
+  "Return the full path of the file represented by LINE-INFO."
+  (expand-file-name
+   (svn-status-line-info->filename line-info)))
+
+;;Not convinced that this is the fastest way, but...
+(defun svn-status-count-/ (string)
+  "Return number of \"/\"'s in STRING."
+  (let ((n 0)
+        (last 0))
+    (while (setq last (string-match "/" string (1+ last)))
+      (setq n (1+ n)))
+    n))
+
+(defun svn-insert-line-in-status-buffer (line-info)
+  "Format LINE-INFO and insert the result in the current buffer."
+  (let ((usermark (if (svn-status-line-info->has-usermark line-info) "*" " "))
+        (external (if (svn-status-line-info->modified-external line-info)
+                      (svn-add-face (if svn-status-short-mod-flag-p
+                                        "** "
+                                      " (modified external)")
+                                    'svn-status-modified-external-face)
+                    (if svn-status-short-mod-flag-p "   " "")))
+        ;; To add indentation based on the
+        ;; directory that the file is in, we just insert 2*(number of "/" in
+        ;; filename) spaces, which is rather hacky (but works)!
+        (filename (svn-status-choose-face-to-add
+                   (svn-status-line-info->directory-p line-info)
+                   (concat (make-string
+                            (* 2 (svn-status-count-/
+                                  (svn-status-line-info->filename line-info)))
+                            32)
+                           (if svn-status-hide-unmodified
+                               (svn-status-line-info->filename line-info)
+                             (svn-status-line-info->filename-nondirectory line-info)))
+                   'svn-status-directory-face
+                   'svn-status-filename-face))
+        (elide-hint (if (svn-status-line-info->show-user-elide-continuation line-info) " ..." "")))
+    (insert (svn-status-maybe-add-face
+             (svn-status-line-info->has-usermark line-info)
+             (concat usermark
+                     (format svn-status-line-format
+                             (svn-status-line-info->filemark line-info)
+                             (or (svn-status-line-info->propmark line-info) ? )
+                             (or (svn-status-line-info->localrev line-info) "")
+                             (or (svn-status-line-info->lastchangerev line-info) "")
+                             (svn-status-line-info->author line-info)))
+             'svn-status-marked-face)
+            (if svn-status-short-mod-flag-p external filename)
+            (if svn-status-short-mod-flag-p filename external)
+            elide-hint
+            "\n")))
+
+(defun svn-status-update-buffer ()
+  (interactive)
+  ;(message (format "buffer-name: %s" (buffer-name)))
+  (unless (string= (buffer-name) "*svn-status*")
+    (delete-other-windows)
+    (split-window-vertically)
+    (switch-to-buffer "*svn-status*"))
+  (svn-status-mode)
+  (let ((st-info svn-status-info)
+        (buffer-read-only nil)
+        (start-pos)
+        (overlay)
+        (unmodified-count 0)
+        (unknown-count 0)
+        (marked-count 0)
+        (fname (svn-status-line-info->filename (svn-status-get-line-information)))
+        (fname-pos (point))
+        (column (current-column)))
+    (delete-region (point-min) (point-max))
+    (insert "\n")
+    ;; Insert all files and directories
+    (while st-info
+      (setq start-pos (point))
+      (cond ((svn-status-line-info->has-usermark (car st-info))
+             ;; Show a marked file always
+             (svn-insert-line-in-status-buffer (car st-info)))
+            ((svn-status-line-info->hide-because-user-elide (car st-info))
+             );(message "user wanted to hide %s" (svn-status-line-info->filename (car st-info))))
+            ((svn-status-line-info->hide-because-unknown (car st-info))
+             (setq unknown-count (+ unknown-count 1)))
+            ((svn-status-line-info->hide-because-unmodified (car st-info))
+             (setq unmodified-count (+ unmodified-count 1)))
+            (t
+             (svn-insert-line-in-status-buffer (car st-info))))
+      (when (svn-status-line-info->has-usermark (car st-info))
+        (setq marked-count (+ marked-count 1)))
+      (setq overlay (make-overlay start-pos (point)))
+      (overlay-put overlay 'svn-info (car st-info))
+      (setq st-info (cdr st-info)))
+    ;; Insert status information at the buffer beginning
+    (goto-char (point-min))
+    (insert (format "svn status for directory %s%s\n"
+                    default-directory
+                    (if svn-status-head-revision (format " (status against revision: %s)"
+                                                         svn-status-head-revision)
+                      "")))
+    (when svn-status-base-info
+      (insert (concat "Repository: " (svn-status-base-info->url) "\n")))
+    (when svn-status-hide-unknown
+      (insert
+       (format "%d Unknown files are hidden - press ? to toggle hiding\n"
+               unknown-count)))
+    (when svn-status-hide-unmodified
+      (insert
+       (format "%d Unmodified files are hidden - press _ to toggle hiding\n"
+               unmodified-count)))
+    (insert (format "%d files marked\n" marked-count))
+    (setq svn-start-of-file-list-line-number (+ (count-lines (point-min) (point)) 1))
+    (if fname
+        (progn
+          (goto-char fname-pos)
+          (svn-status-goto-file-name fname)
+          (goto-char (+ column (point-at-bol))))
+      (goto-char (+ (next-overlay-change (point-min)) svn-status-default-column)))))
+
+(defun svn-status-parse-info (arg)
+  "Parse the svn info output for the base directory.
+Show the repository url after this call in the *svn-status* buffer.
+When called with the prefix argument 0, reset the information to nil.
+This hides the repository information again."
+  (interactive "P")
+  (if (eq arg 0)
+      (setq svn-status-base-info nil)
+    (svn-run-svn nil t 'parse-info "info" ".")
+    (svn-status-parse-info-result))
+  (svn-status-update-buffer))
+
+(defun svn-status-parse-info-result ()
+  (let ((url))
+    (save-excursion
+      (set-buffer "*svn-process*")
+      (goto-char (point-min))
+      (search-forward "Url: ")
+      (setq url (buffer-substring-no-properties (point) (point-at-eol))))
+    (setq svn-status-base-info `((url ,url)))))
+
+(defun svn-status-base-info->url ()
+  (if svn-status-base-info
+      (cadr (assoc 'url svn-status-base-info))
+    ""))
+
+(defun svn-status-toggle-edit-cmd-flag (&optional reset)
+  (interactive)
+  (cond ((or reset (eq svn-status-edit-svn-command 'sticky))
+         (setq svn-status-edit-svn-command nil))
+        ((eq svn-status-edit-svn-command nil)
+         (setq svn-status-edit-svn-command t))
+        ((eq svn-status-edit-svn-command t)
+         (setq svn-status-edit-svn-command 'sticky)))
+  (cond ((eq svn-status-edit-svn-command t)
+         (setq svn-status-mode-line-process-edit-flag " EditCmd"))
+        ((eq svn-status-edit-svn-command 'sticky)
+         (setq svn-status-mode-line-process-edit-flag " EditCmd#"))
+        (t
+         (setq svn-status-mode-line-process-edit-flag "")))
+  (svn-status-update-mode-line))
+
+(defun svn-status-goto-root-or-return ()
+  "Bounce point between the root (\".\") and the current line."
+  (interactive)
+  (if (string= (svn-status-line-info->filename (svn-status-get-line-information)) ".")
+      (when svn-status-root-return-info
+        (svn-status-goto-file-name
+         (svn-status-line-info->filename svn-status-root-return-info)))
+    (setq svn-status-root-return-info (svn-status-get-line-information))
+    (svn-status-goto-file-name ".")))
+
+(defun svn-status-next-line (nr-of-lines)
+  (interactive "p")
+  (next-line nr-of-lines)
+  (when (svn-status-get-line-information)
+    (goto-char (+ (point-at-bol) svn-status-default-column))))
+
+(defun svn-status-previous-line (nr-of-lines)
+  (interactive "p")
+  (previous-line nr-of-lines)
+  (when (svn-status-get-line-information)
+    (goto-char (+ (point-at-bol) svn-status-default-column))))
+
+(defun svn-status-update (&optional arg)
+  "Run 'svn status -v'.
+When called with a prefix argument run 'svn status -vu'."
+  (interactive "P")
+  (unless (interactive-p)
+    (save-excursion
+      (set-buffer "*svn-process*")
+      (setq svn-status-update-previous-process-output (buffer-substring (point-min) (point-max)))))
+  (svn-status default-directory arg))
+
+(defun svn-status-get-line-information ()
+  "Find out about the file under point.
+The result may be parsed with the various `svn-status-line-info->...' functions."
+  (let ((overlay (car (overlays-at (point)))))
+    (when overlay
+      (overlay-get overlay 'svn-info))))
+
+(defun svn-status-get-file-list (use-marked-files)
+  "Get either the marked files or the files, where the cursor is on."
+  (if use-marked-files
+      (svn-status-marked-files)
+    (list (svn-status-get-line-information))))
+
+(defun svn-status-get-file-list-names (use-marked-files)
+  (mapcar 'svn-status-line-info->filename (svn-status-get-file-list use-marked-files)))
+
+(defun svn-status-select-line ()
+  (interactive)
+  (let ((info (svn-status-get-line-information)))
+    (if info
+        (message "%S %S %S" info (svn-status-line-info->hide-because-unknown info)
+                                 (svn-status-line-info->hide-because-unmodified info))
+      (message "No file on this line"))))
+
+(defun svn-status-directory-containing-point (allow-self)
+  "Find the (full path of) directory containing the file under point.
+
+If ALLOW-SELF and the file is a directory, return that directory,
+otherwise return the directory containing the file under point."
+  ;;the first `or' below is because s-s-g-l-i returns `nil' if
+  ;;point was outside the file list, but we need
+  ;;s-s-l-i->f to return a string to add to `default-directory'.
+  (let ((line-info (or (svn-status-get-line-information)
+                       '(nil nil nil ""))))
+    (file-name-as-directory
+     (expand-file-name
+      (if (and allow-self (svn-status-line-info->directory-p line-info))
+          (svn-status-line-info->filename line-info)
+        ;;The next `or' is because (file-name-directory "file") returns nil
+        (or (file-name-directory (svn-status-line-info->filename line-info))
+            "."))))))
+
+(defun svn-status-set-user-mark (arg)
+  "Set a user mark on the current file or directory.
+If the cursor is on a file this file is marked and the cursor advances to the next line.
+If the cursor is on a directory all files in this directory are marked.
+
+If this function is called with a prefix argument, only the current line is
+marked, even if it is a directory."
+  (interactive "P")
+  (let ((info (svn-status-get-line-information)))
+    (if info
+        (progn
+          (svn-status-apply-usermark t arg)
+          (svn-status-next-line 1))
+      (message "No file on this line - cannot set a mark"))))
+
+(defun svn-status-unset-user-mark (arg)
+  "Remove a user mark on the current file or directory.
+If the cursor is on a file, this file is unmarked and the cursor advances to the next line.
+If the cursor is on a directory, all files in this directory are unmarked.
+
+If this function is called with a prefix argument, only the current line is
+unmarked, even if is a directory."
+  (interactive "P")
+  (let ((info (svn-status-get-line-information)))
+    (if info
+        (progn
+          (svn-status-apply-usermark nil arg)
+          (svn-status-next-line 1))
+      (message "No file on this line - cannot unset a mark"))))
+
+(defun svn-status-unset-user-mark-backwards ()
+  "Remove a user mark from the previous file.
+Then move to that line."
+  ;; This is consistent with `dired-unmark-backward' and
+  ;; `cvs-mode-unmark-up'.
+  (interactive)
+  (let ((info (save-excursion
+                (svn-status-next-line -1)
+                (svn-status-get-line-information))))
+    (if info
+        (progn
+          (svn-status-next-line -1)
+          (svn-status-apply-usermark nil t))
+      (message "No file on previous line - cannot unset a mark"))))
+
+(defun svn-status-apply-usermark (set-mark only-this-line)
+  "Do the work for the various marking/unmarking functions."
+  (let* ((st-info svn-status-info)
+         (line-info (svn-status-get-line-information))
+         (file-name (svn-status-line-info->filename line-info))
+     (sub-file-regexp (concat "^" (regexp-quote
+                       (file-name-as-directory file-name))))
+         (newcursorpos-fname)
+         (i-fname)
+         (current-line svn-start-of-file-list-line-number))
+    (while st-info
+      (when (svn-status-line-info->is-visiblep (car st-info))
+        (setq current-line (1+ current-line)))
+      (setq i-fname (svn-status-line-info->filename (car st-info)))
+      (when (or (string= file-name i-fname)
+        (string-match sub-file-regexp i-fname))
+        (when (svn-status-line-info->is-visiblep (car st-info))
+          (when (or (not only-this-line) (string= file-name i-fname))
+            (setq newcursorpos-fname i-fname)
+            (if set-mark
+                (message "marking: %s" i-fname)
+              (message "unmarking: %s" i-fname))
+            ;;(message "ui-status: %S" (svn-status-line-info->ui-status (car st-info)))
+            (setcar (svn-status-line-info->ui-status (car st-info)) set-mark)
+            (save-excursion
+              (let ((buffer-read-only nil))
+                (goto-line current-line)
+                (delete-region (point-at-bol) (point-at-eol))
+                (svn-insert-line-in-status-buffer (car st-info))
+                (delete-char 1))))))
+      (setq st-info (cdr st-info)))
+    ;;(svn-status-update-buffer)
+    (svn-status-goto-file-name newcursorpos-fname)))
+
+(defun svn-status-apply-usermark-checked (check-function set-mark)
+  "Mark or unmark files, whether a given function returns t.
+The function is called with the line information. Therefore the svnstatus-line-info->* functions can be
+used in the check."
+  (let ((st-info svn-status-info))
+    (while st-info
+      (when (apply check-function (list (car st-info)))
+        (if set-mark
+            (when (not (svn-status-line-info->has-usermark (car st-info)))
+              (message "marking: %s" (svn-status-line-info->filename (car st-info))))
+          (when (svn-status-line-info->has-usermark (car st-info))
+            (message "unmarking: %s" (svn-status-line-info->filename (car st-info)))))
+        (setcar (svn-status-line-info->ui-status (car st-info)) set-mark))
+      (setq st-info (cdr st-info)))
+    (svn-status-update-buffer)))
+
+(defun svn-status-mark-unknown (arg)
+  "Mark all unknown files.
+These are the files marked with '?' in the *svn-status* buffer.
+If the function is called with a prefix arg, unmark all these files."
+  (interactive "P")
+  (svn-status-apply-usermark-checked '(lambda (info) (eq (svn-status-line-info->filemark info) ??)) (not arg)))
+
+(defun svn-status-mark-added (arg)
+  "Mark all added files.
+These are the files marked with 'A' in the *svn-status* buffer.
+If the function is called with a prefix arg, unmark all these files."
+  (interactive "P")
+  (svn-status-apply-usermark-checked '(lambda (info) (eq (svn-status-line-info->filemark info) ?A)) (not arg)))
+
+(defun svn-status-mark-modified (arg)
+  "Mark all modified files.
+These are the files marked with 'M' in the *svn-status* buffer.
+If the function is called with a prefix arg, unmark all these files."
+  (interactive "P")
+  (svn-status-apply-usermark-checked '(lambda (info) (eq (svn-status-line-info->filemark info) ?M)) (not arg)))
+
+(defun svn-status-unset-all-usermarks ()
+  (interactive)
+  (svn-status-apply-usermark-checked '(lambda (info) t) nil))
+
+(defun svn-status-toggle-hide-unknown ()
+  (interactive)
+  (setq svn-status-hide-unknown (not svn-status-hide-unknown))
+  (svn-status-update-buffer))
+
+(defun svn-status-toggle-hide-unmodified ()
+  (interactive)
+  (setq svn-status-hide-unmodified (not svn-status-hide-unmodified))
+  (svn-status-update-buffer))
+
+(defun svn-status-goto-file-name (name)
+  ;; (message "svn-status-goto-file-name: %s %d" name (point))
+  (let ((start-pos (point)))
+    (goto-char (point-min))
+    (while (< (point) (point-max))
+      (goto-char (next-overlay-change (point)))
+      (when (string= name (svn-status-line-info->filename
+                           (svn-status-get-line-information)))
+        (setq start-pos (+ (point) svn-status-default-column))))
+    (goto-char start-pos)))
+
+(defun svn-status-find-info-for-file-name (name)
+  (let* ((st-info svn-status-info)
+         (info))
+    (while st-info
+      (when (string= name (svn-status-line-info->filename (car st-info)))
+        (setq info (car st-info))
+        (setq st-info nil)) ; terminate loop
+      (setq st-info (cdr st-info)))
+    info))
+
+(defun svn-status-marked-files ()
+  "Return all files marked by `svn-status-set-user-mark',
+or (if no files were marked) the file under point."
+  (let* ((st-info svn-status-info)
+         (file-list))
+    (while st-info
+      (when (svn-status-line-info->has-usermark (car st-info))
+        (setq file-list (append file-list (list (car st-info)))))
+      (setq st-info (cdr st-info)))
+    (or file-list
+        (if (svn-status-get-line-information)
+            (list (svn-status-get-line-information))
+          nil))))
+
+(defun svn-status-marked-file-names ()
+  (mapcar 'svn-status-line-info->filename (svn-status-marked-files)))
+
+(defun svn-status-ui-information-hash-table ()
+  (let ((st-info svn-status-info)
+        (svn-status-ui-information (make-hash-table :test 'equal)))
+    (while st-info
+      (puthash (svn-status-line-info->filename (car st-info))
+               (svn-status-line-info->ui-status (car st-info))
+               svn-status-ui-information)
+      (setq st-info (cdr st-info)))
+    svn-status-ui-information))
+
+
+(defun svn-status-create-arg-file (file-name prefix file-info-list postfix)
+  (with-temp-file file-name
+    (insert prefix)
+    (let ((st-info file-info-list))
+      (while st-info
+        (insert (svn-status-line-info->filename (car st-info)))
+        (insert "\n")
+        (setq st-info (cdr st-info)))
+
+    (insert postfix))))
+
+(defun svn-status-show-process-buffer-internal (&optional scroll-to-top)
+  (when (eq (current-buffer) "*svn-status*")
+    (delete-other-windows))
+  (pop-to-buffer "*svn-process*")
+  (when svn-status-wash-control-M-in-process-buffers
+    (svn-status-remove-control-M))
+  (when scroll-to-top
+    (goto-char (point-min)))
+  (other-window 1))
+
+(defun svn-status-show-svn-log (arg)
+  "Run `svn log' on selected files.
+When called with a prefix argument add the following command switches:
+ no prefix:              use whatever is in the string `svn-status-default-log-arguments'
+ prefix argument of -1:  use no arguments
+ prefix argument of 0:   use the -q switch (quiet)
+ other prefix arguments: use the -v switch (verbose)
+
+See `svn-status-marked-files' for what counts as selected."
+  (interactive "P")
+  (let ((switch (cond ((eq arg 0) "-q")
+                      ((eq arg -1) "")
+                      (arg        "-v")
+                      (t          svn-status-default-log-arguments))))
+    ;;(message "show log info for: %S" (svn-status-marked-files))
+    (svn-status-create-arg-file svn-status-temp-arg-file "" (svn-status-marked-files) "")
+    (if (> (length switch) 0)
+        (svn-run-svn t t 'log "log" "--targets" svn-status-temp-arg-file switch)
+      (svn-run-svn t t 'log "log" "--targets" svn-status-temp-arg-file))
+    (save-excursion
+      (set-buffer "*svn-process*")
+      (svn-log-view-mode))))
+
+(defun svn-status-info ()
+  "Run `svn info' on all selected files.
+See `svn-status-marked-files' for what counts as selected."
+  (interactive)
+  (svn-status-create-arg-file svn-status-temp-arg-file "" (svn-status-marked-files) "")
+  (svn-run-svn t t 'info "info" "--targets" svn-status-temp-arg-file))
+
+;; Todo: add possiblity to specify the revision
+(defun svn-status-blame ()
+  "Run `svn blame' on the current file."
+  (interactive)
+  ;;(svn-run-svn t t 'blame "blame" "-r" "BASE" (svn-status-line-info->filename (svn-status-get-line-information))))
+  (svn-run-svn t t 'blame "blame" (svn-status-line-info->filename (svn-status-get-line-information))))
+
+(defun svn-status-show-svn-diff (arg)
+  "Run `svn diff' on the current file.
+If there is a newer revision in the repository, the diff is done against HEAD, otherwise
+compare the working copy with BASE.
+If ARG then prompt for revision to diff against."
+  (interactive "P")
+  (svn-status-show-svn-diff-internal arg nil))
+
+(defun svn-status-show-svn-diff-for-marked-files (arg)
+  "Run `svn diff' on all selected files.
+See `svn-status-marked-files' for what counts as selected.
+If ARG then prompt for revision to diff against, else compare working copy with BASE."
+  (interactive "P")
+  (svn-status-show-svn-diff-internal arg t))
+
+(defun svn-status-show-svn-diff-internal (arg &optional use-all-marked-files)
+  (let* ((fl (if use-all-marked-files
+                 (svn-status-marked-files)
+               (list (svn-status-get-line-information))))
+         (clear-buf t)
+         (revision (if arg
+                       (svn-status-read-revision-string "Diff with files for version: " "PREV")
+                     (if use-all-marked-files
+                         "BASE"
+                       (if (svn-status-line-info->modified-external (car fl)) "HEAD" "BASE")))))
+    (while fl
+      (svn-run-svn nil clear-buf 'diff "diff" "-r" revision (svn-status-line-info->filename (car fl)))
+      (setq clear-buf nil)
+      (setq fl (cdr fl))))
+  (svn-status-show-process-buffer-internal t)
+  (save-excursion
+    (set-buffer "*svn-process*")
+    (diff-mode)
+    (font-lock-fontify-buffer)))
+
+(defun svn-status-show-process-buffer ()
+  (interactive)
+  (svn-status-show-process-buffer-internal))
+
+(defun svn-status-add-file-recursively (arg)
+  "Run `svn add' on all selected files.
+When a directory is added, add files recursively.
+See `svn-status-marked-files' for what counts as selected.
+When this function is called with a prefix argument, use the actual file instead."
+  (interactive "P")
+  (message "adding: %S" (svn-status-get-file-list-names (not arg)))
+  (svn-status-create-arg-file svn-status-temp-arg-file "" (svn-status-get-file-list (not arg)) "")
+  (svn-run-svn t t 'add "add" "--targets" svn-status-temp-arg-file))
+
+(defun svn-status-add-file (arg)
+  "Run `svn add' on all selected files.
+When a directory is added, don't add the files of the directory
+ (svn add --non-recursive <file-list> is called).
+See `svn-status-marked-files' for what counts as selected.
+When this function is called with a prefix argument, use the actual file instead."
+  (interactive "P")
+  (message "adding: %S" (svn-status-get-file-list-names (not arg)))
+  (svn-status-create-arg-file svn-status-temp-arg-file "" (svn-status-get-file-list (not arg)) "")
+  (svn-run-svn t t 'add "add" "--non-recursive" "--targets" svn-status-temp-arg-file))
+
+(defun svn-status-make-directory (dir)
+  "Run `svn mkdir DIR'."
+  ;; TODO: Allow entering a URI interactively.
+  ;; Currently, `read-file-name' corrupts it.
+  (interactive (list (read-file-name "Make directory: "
+                                     (svn-status-directory-containing-point t))))
+  (unless (string-match "^[^:/]+://" dir) ; Is it a URI?
+    (setq dir (file-relative-name dir)))
+  (svn-run-svn t t 'mkdir "mkdir" "--" dir))
+
+;;TODO: write a svn-status-cp similar to this---maybe a common
+;;function to do both?
+(defun svn-status-mv ()
+  "Prompt for a destination, and `svn mv' selected files there.
+See `svn-status-marked-files' for what counts as `selected'.
+
+If one file was selected then the destination DEST should be a
+filename to rename the selected file to, or a directory to move the
+file into; if multiple files were selected then DEST should be a
+directory to move the selected files into.
+
+The default DEST is the directory containing point.
+
+BUG: If we've marked some directory containging a file as well as the
+file itself, then we should just mv the directory, but this implementation
+doesn't check for that.
+SOLUTION: for each dir, umark all its contents (but not the dir
+itself) before running mv."
+  (interactive)
+  (let* ((marked-files (svn-status-marked-files))
+         (num-of-files (length marked-files))
+         original
+         dest)
+    (if (= 1 num-of-files)
+        ;; one file to rename, prompt for new name, or directory to move the
+        ;; file into.
+        (setq dest (read-file-name (format "Rename %s to: "
+                                           (svn-status-line-info->filename (car marked-files)))
+                                   (svn-status-directory-containing-point t)))
+      ;;multiple files selected, so prompt for existing directory to mv them into.
+      (setq dest (read-directory-name (format "Move %d files to directory: " num-of-files)
+                                      (svn-status-directory-containing-point t) nil t))
+      (unless (file-directory-p dest)
+        (error "%s is not a directory" dest)))
+    (when (string= dest "")
+      (error "No destination entered; no files moved"))
+    (unless (string-match "^[^:/]+://" dest) ; Is it a URI?
+      (setq dest (file-relative-name dest)))
+;
+    ;;do the move: svn mv only lets us move things once at a time, so
+    ;;we need to run svn mv once for each file (hence second arg to
+    ;;svn-run-svn is nil.)
+
+    ;;TODO: before doing any moving, For every marked directory,
+    ;;ensure none of its contents are also marked, since we dont want
+    ;;to move both file *and* its parent...
+    ;; what about hidden files?? what if user marks a dir+contents, then presses `_' ??
+;;   ;one solution:
+;;      (dolist (original marked-files)
+;;          (when (svn-status-line-info->directory-p original)
+;;              ;; run  svn-status-goto-file-name to move point to line of file
+;;              ;; run  svn-status-unset-user-mark to unmark dir+all contents
+;;              ;; run  svn-status-set-user-mark   to remark dir
+;;              ;; maybe check for local mods here, and unmark if user does't say --force?
+;;              ))
+        (dolist (original marked-files)
+      (let ((original-name (svn-status-line-info->filename original))
+                        (original-filemarks (svn-status-line-info->filemark original))
+                        (original-propmarks (svn-status-line-info->propmark original)))
+        (cond
+         ((or (eq original-filemarks 77)  ;;original has local mods: maybe do `svn mv --force'
+              (eq original-propmarks 77)) ;;original has local prop mods: maybe do `svn mv --force'
+          (if (yes-or-no-p (format "%s has local modifications; use `--force' to really move it? "
+                                   original-name))
+              (svn-run-svn nil t 'mv "mv" "--force" "--" original-name dest)
+            (message "Not moving %s" original-name)))
+         ((eq original-filemarks 63) ;;original is unversioned: maybe do plain `mv'
+          (if (yes-or-no-p (format "%s is unversioned.  Use plain `mv -i %s %s'? "
+                                   original-name original-name dest))
+              (call-process "mv" nil (get-buffer-create "*svn-process*") nil "-i" original-name dest)
+            (message "Not moving %s" original-name)))
+
+         ((eq original-filemarks 65) ;;original has `A' mark (eg it was `svn add'ed, but not committed)
+          (message "Not moving %s (try committing it first)" original-name))
+
+         ((eq original-filemarks 32) ;;original is unmodified: can use `svn mv'
+          (svn-run-svn nil t 'mv "mv" "--" original-name dest))
+
+         ;;file is conflicted in some way?
+         (t
+          (if (yes-or-no-p (format "The status of %s looks scary.  Risk moving it anyway? " original-name))
+              (svn-run-svn nil t 'mv "mv" "--" original-name dest)
+            (message "Not moving %s" original-name))))))
+        (svn-status-update)))
+
+(defun svn-status-revert ()
+  "Run `svn revert' on all selected files.
+See `svn-status-marked-files' for what counts as selected."
+  (interactive)
+  (let* ((marked-files (svn-status-marked-files))
+         (num-of-files (length marked-files)))
+    (when (yes-or-no-p
+           (if (= 1 num-of-files)
+               (format "Revert %s? " (svn-status-line-info->filename (car marked-files)))
+             (format "Revert %d files? " num-of-files)))
+      (message "reverting: %S" (svn-status-marked-file-names))
+      (svn-status-create-arg-file svn-status-temp-arg-file "" (svn-status-marked-files) "")
+      (svn-run-svn t t 'revert "revert" "--targets" svn-status-temp-arg-file))))
+
+(defun svn-status-rm (force)
+  "Run `svn rm' on all selected files.
+See `svn-status-marked-files' for what counts as selected.
+When called with a prefix argument add the command line switch --force."
+  (interactive "P")
+  (let* ((marked-files (svn-status-marked-files))
+         (num-of-files (length marked-files)))
+    (when (yes-or-no-p
+           (if (= 1 num-of-files)
+               (format "%sRemove %s? " (if force "Force " "") (svn-status-line-info->filename (car marked-files)))
+             (format "%sRemove %d files? " (if force "Force " "") num-of-files)))
+      (message "removing: %S" (svn-status-marked-file-names))
+      (svn-status-create-arg-file svn-status-temp-arg-file "" (svn-status-marked-files) "")
+      (if force
+          (svn-run-svn t t 'rm "rm" "--force" "--targets" svn-status-temp-arg-file)
+        (svn-run-svn t t 'rm "rm" "--targets" svn-status-temp-arg-file)))))
+
+(defun svn-status-update-cmd ()
+  (interactive)
+  ;TODO: use file names also
+  (svn-run-svn t t 'update "update"))
+
+(defun svn-status-commit-file ()
+  (interactive)
+  (let* ((marked-files (svn-status-marked-files)))
+    (setq svn-status-files-to-commit marked-files)
+    (svn-log-edit-show-files-to-commit)
+    (svn-status-pop-to-commit-buffer)))
+
+(defun svn-status-pop-to-commit-buffer ()
+  (interactive)
+  (setq svn-status-pre-commit-window-configuration (current-window-configuration))
+  (let* ((use-existing-buffer (get-buffer "*svn-log-edit*"))
+         (commit-buffer (get-buffer-create "*svn-log-edit*"))
+         (dir default-directory))
+    (pop-to-buffer commit-buffer)
+    (setq default-directory dir)
+    (unless use-existing-buffer
+      (when (and svn-log-edit-file-name (file-readable-p svn-log-edit-file-name))
+        (insert-file svn-log-edit-file-name)))
+    (svn-log-edit-mode)))
+
+(defun svn-status-cleanup ()
+  (interactive)
+  (let ((file-names (svn-status-marked-file-names)))
+    (if file-names
+        (progn
+          ;(message "svn-status-cleanup %S" file-names))
+          (svn-run-svn t t 'cleanup (append (list "cleanup") file-names)))
+      (message "No valid file selected - No status cleanup possible"))))
+
+(defun svn-status-resolved ()
+  "Run `svn resolved' on all selected files.
+See `svn-status-marked-files' for what counts as selected."
+  (interactive)
+  (let* ((marked-files (svn-status-marked-files))
+         (num-of-files (length marked-files)))
+    (when (yes-or-no-p
+           (if (= 1 num-of-files)
+               (format "Resolve %s? " (svn-status-line-info->filename (car marked-files)))
+             (format "Resolve %d files? " num-of-files)))
+      (message "resolving: %S" (svn-status-marked-file-names))
+      (svn-status-create-arg-file svn-status-temp-arg-file "" (svn-status-marked-files) "")
+      (svn-run-svn t t 'resolved "resolved" "--targets" svn-status-temp-arg-file))))
+
+;; --------------------------------------------------------------------------------
+;; Update the *svn-status* buffer, when a file is saved
+;; --------------------------------------------------------------------------------
+
+(defvar svn-status-file-modified-after-save-flag ?m
+  "The flag, that is shown, in the *svn-status* buffer, after
+a file is changed and saved in emacs.
+Recommended values are ?m or ?M.")
+(defun svn-status-after-save-hook ()
+  "Set a modified indication, when a file is saved from a svn working copy."
+  (let* ((svn-dir (car-safe svn-status-directory-history))
+         (svn-dir (when svn-dir (expand-file-name svn-dir)))
+         (file-dir (file-name-directory (buffer-file-name)))
+         (svn-dir-len (length (or svn-dir "")))
+         (file-dir-len (length file-dir))
+         (file-name))
+    (when (and svn-dir
+               (>= file-dir-len svn-dir-len)
+               (string= (substring file-dir 0 svn-dir-len) svn-dir))
+      (setq file-name (substring (buffer-file-name) svn-dir-len))
+      ;;(message (format "In svn-status directory %S" file-name))
+      (let ((st-info svn-status-info)
+            (i-fname))
+        (while st-info
+          (setq i-fname (svn-status-line-info->filename (car st-info)))
+          ;;(message (format "i-fname=%S" i-fname))
+          (when (and (string= file-name i-fname)
+                     (not (eq (svn-status-line-info->filemark (car st-info)) ??)))
+            (svn-status-line-info->set-filemark (car st-info)
+                                                svn-status-file-modified-after-save-flag)
+            (save-excursion
+              (set-buffer "*svn-status*")
+              (svn-status-goto-file-name i-fname)
+              (let ((buffer-read-only nil))
+                (delete-region (point-at-bol) (point-at-eol))
+                (svn-insert-line-in-status-buffer (car st-info))
+                (delete-char 1))))
+          (setq st-info (cdr st-info))))))
+  nil)
+
+(add-hook 'after-save-hook 'svn-status-after-save-hook)
+
+;; --------------------------------------------------------------------------------
+;; Getting older revisions
+;; --------------------------------------------------------------------------------
+
+(defun svn-status-get-specific-revision (arg)
+  "Retrieve older revisions.
+The older revisions are stored in backup files named F.~REVISION~.
+
+When the function is called without a prefix argument: get all marked files.
+Otherwise get only the actual file."
+  (interactive "P")
+  (svn-status-get-specific-revision-internal (not arg) t))
+
+(defun svn-status-get-specific-revision-internal (&optional only-actual-file arg)
+  (let* ((file-names (if only-actual-file
+                         (list (svn-status-line-info->filename (svn-status-get-line-information)))
+                       (svn-status-marked-file-names)))
+         (revision (if arg (svn-status-read-revision-string "Get files for version: " "PREV") "BASE"))
+         (file-name)
+         (file-name-with-revision))
+    (message "Getting revision %s for %S" revision file-names)
+    (setq svn-status-get-specific-revision-file-info nil)
+    (while file-names
+      (setq file-name (car file-names))
+      (setq file-name-with-revision (concat file-name ".~" revision "~"))
+      (add-to-list 'svn-status-get-specific-revision-file-info
+                   (cons file-name file-name-with-revision))
+      (save-excursion
+        (find-file file-name-with-revision)
+        (setq buffer-read-only nil)
+        (delete-region (point-min) (point-max))
+        (svn-run-svn nil t 'cat (append (list "cat" "-r" revision) (list file-name)))
+        ;;todo: error processing
+        ;;svn: Filesystem has no item
+        ;;svn: file not found: revision `15', path `/trunk/file.txt'
+        (insert-buffer-substring "*svn-process*")
+        (save-buffer))
+      (setq file-names (cdr file-names)))
+    (setq svn-status-get-specific-revision-file-info
+      (nreverse svn-status-get-specific-revision-file-info))
+    (message "svn-status-get-specific-revision-file-info: %S"
+             svn-status-get-specific-revision-file-info)))
+
+
+(defun svn-status-ediff-with-revision (arg)
+  "Run ediff on the current file with a previous revision.
+If ARG then prompt for revision to diff against."
+  (interactive "P")
+  (svn-status-get-specific-revision-internal t arg)
+  (let* ((ediff-after-quit-destination-buffer (current-buffer))
+         (my-buffer (find-file-noselect (caar svn-status-get-specific-revision-file-info)))
+         (base-buff (find-file-noselect (cdar svn-status-get-specific-revision-file-info)))
+         (svn-transient-buffers (list base-buff ))
+         (startup-hook '(svn-ediff-startup-hook)))
+    (ediff-buffers my-buffer base-buff  startup-hook)))
+
+(defun svn-ediff-startup-hook ()
+  (add-hook 'ediff-after-quit-hook-internal
+        `(lambda ()
+           (svn-ediff-exit-hook
+        ',ediff-after-quit-destination-buffer ',svn-transient-buffers))
+        nil 'local))
+
+(defun svn-ediff-exit-hook (svn-buf tmp-bufs)
+  ;; kill the temp buffers (and their associated windows)
+  (dolist (tb tmp-bufs)
+    (when (and tb (buffer-live-p tb) (not (buffer-modified-p tb)))
+      (let ((win (get-buffer-window tb t)))
+    (when win (delete-window win))
+    (kill-buffer tb))))
+  ;; switch back to the *svn* buffer
+  (when (and svn-buf (buffer-live-p svn-buf)
+         (not (get-buffer-window svn-buf t)))
+    (ignore-errors (switch-to-buffer svn-buf))))
+
+
+(defun svn-status-read-revision-string (prompt &optional default-value)
+  "Prompt the user for a svn revision number."
+  (interactive)
+  (read-string prompt default-value))
+
+;; --------------------------------------------------------------------------------
+;; SVN process handling
+;; --------------------------------------------------------------------------------
+
+(defun svn-process-kill ()
+  "Kill the current running svn process."
+  (interactive)
+  (let ((process (get-process "svn")))
+    (if process
+        (delete-process process)
+      (message "No running svn process"))))
+
+(defun svn-process-send-string (string)
+  "Send a string to the running svn process.
+This is useful, if the running svn process asks the user a question.
+Note: use C-q C-j to send a line termination character."
+  (interactive "sSend string to svn process: ")
+  (save-excursion
+    (set-buffer "*svn-process*")
+    (let ((buffer-read-only nil))
+      (insert string))
+    (set-marker (process-mark (get-process "svn")) (point)))
+  (process-send-string "svn" string))
+
+;; --------------------------------------------------------------------------------
+;; Property List stuff
+;; --------------------------------------------------------------------------------
+
+(defun svn-status-property-list ()
+  (interactive)
+  (let ((file-names (svn-status-marked-file-names)))
+    (if file-names
+        (progn
+          (svn-run-svn t t 'proplist (append (list "proplist" "-v") file-names)))
+      (message "No valid file selected - No property listing possible"))))
+
+(defun svn-status-proplist-start ()
+  (svn-run-svn t t 'proplist-parse "proplist" (svn-status-line-info->filename
+                                               (svn-status-get-line-information))))
+
+(defun svn-status-property-parse ()
+  (interactive)
+  (svn-status-proplist-start))
+
+(defun svn-status-property-edit-one-entry (arg)
+  "Edit a property.
+When called with a prefix argument, it is possible to enter a new property."
+  (interactive "P")
+  (setq svn-status-property-edit-must-match-flag (not arg))
+  (svn-status-proplist-start))
+
+(defun svn-status-property-set ()
+  (interactive)
+  (setq svn-status-property-edit-must-match-flag nil)
+  (svn-status-proplist-start))
+
+(defun svn-status-property-delete ()
+  (interactive)
+  (setq svn-status-property-edit-must-match-flag t)
+  (svn-status-proplist-start))
+
+(defun svn-status-property-parse-property-names ()
+  ;(svn-status-show-process-buffer-internal t)
+  (message "svn-status-property-parse-property-names")
+  (let ((pl)
+        (pfl)
+        (prop-name)
+        (prop-value))
+    (save-excursion
+      (set-buffer "*svn-process*")
+      (goto-char (point-min))
+      (forward-line 1)
+      (while (looking-at "  \\(.+\\)")
+        (setq pl (append pl (list (match-string 1))))
+        (forward-line 1)))
+    ;(cond last-command: svn-status-property-set, svn-status-property-edit-one-entry
+    ;svn-status-property-parse:
+    (cond ((eq last-command 'svn-status-property-parse)
+           ;(message "%S %S" pl last-command)
+           (while pl
+             (svn-run-svn nil t 'propget-parse "propget" (car pl)
+                          (svn-status-line-info->filename
+                           (svn-status-get-line-information)))
+             (save-excursion
+               (set-buffer "*svn-process*")
+               (setq pfl (append pfl (list
+                                      (list
+                                       (car pl)
+                                       (buffer-substring
+                                        (point-min) (- (point-max) 1)))))))
+             (setq pl (cdr pl))
+             (message "%S" pfl)))
+          ((eq last-command 'svn-status-property-edit-one-entry)
+           ;;(message "svn-status-property-edit-one-entry")
+           (setq prop-name
+                 (completing-read "Set Property - Name: " (mapcar 'list pl)
+                                  nil svn-status-property-edit-must-match-flag))
+           (unless (string= prop-name "")
+             (save-excursion
+               (set-buffer "*svn-status*")
+               (svn-status-property-edit (list (svn-status-get-line-information))
+                                         prop-name))))
+          ((eq last-command 'svn-status-property-set)
+           (message "svn-status-property-set")
+           (setq prop-name
+                 (completing-read "Set Property - Name: " (mapcar 'list pl) nil nil))
+           (setq prop-value (read-from-minibuffer "Property value: "))
+           (unless (string= prop-name "")
+             (save-excursion
+               (set-buffer "*svn-status*")
+               (message "setting property %s := %s for %S" prop-name prop-value
+                        (svn-status-marked-files)))))
+          ((eq last-command 'svn-status-property-delete)
+           (setq prop-name
+                 (completing-read "Delete Property - Name: " (mapcar 'list pl) nil t))
+           (unless (string= prop-name "")
+             (save-excursion
+               (set-buffer "*svn-status*")
+               (let ((file-names (svn-status-marked-file-names)))
+                 (when file-names
+                   (message "Going to delete prop %s for %s" prop-name file-names)
+                   (svn-run-svn t t 'propdel
+                                (append (list "propdel" prop-name) file-names))))))))))
+
+(defun svn-status-property-edit (file-info-list prop-name &optional new-prop-value)
+  (let* ((commit-buffer (get-buffer-create "*svn-property-edit*"))
+         (dir default-directory)
+         ;; now only one file is implemented ...
+         (file-name (svn-status-line-info->filename (car file-info-list)))
+         (prop-value))
+    (message "Edit property %s for file %s" prop-name file-name)
+    (svn-run-svn nil t 'propget-parse "propget" prop-name file-name)
+    (save-excursion
+      (set-buffer "*svn-process*")
+      (setq prop-value (if (> (point-max) 1)
+                           (buffer-substring (point-min) (- (point-max) 1))
+                         "")))
+    (setq svn-status-propedit-property-name prop-name)
+    (setq svn-status-propedit-file-list file-info-list)
+    (setq svn-status-pre-propedit-window-configuration (current-window-configuration))
+    (pop-to-buffer commit-buffer)
+    (delete-region (point-min) (point-max))
+    (setq default-directory dir)
+    (insert prop-value)
+    (svn-status-remove-control-M)
+    (when new-prop-value
+      (when (listp new-prop-value)
+        (message "Adding new prop values %S " new-prop-value)
+        (while new-prop-value
+          (goto-char (point-min))
+          (unless (re-search-forward
+                   (concat "^" (regexp-quote (car new-prop-value)) "$") nil t)
+            (goto-char (point-max))
+            (when (> (current-column) 0) (insert "\n"))
+            (insert (car new-prop-value)))
+          (setq new-prop-value (cdr new-prop-value)))))
+    (svn-prop-edit-mode)))
+
+(defun svn-status-property-set-property (file-info-list prop-name prop-value)
+  "Set a property on a given file list."
+  (save-excursion
+    (set-buffer (get-buffer "*svn-property-edit*"))
+    (delete-region (point-min) (point-max))
+    (insert prop-value))
+  (setq svn-status-propedit-file-list (svn-status-marked-files))
+  (setq svn-status-propedit-property-name prop-name)
+  (svn-prop-edit-do-it nil)
+  (svn-status-update))
+
+
+(defun svn-status-get-directory (line-info)
+  (let* ((file-name (svn-status-line-info->filename line-info))
+         (file-dir (file-name-directory file-name)))
+    ;;(message "file-dir: %S" file-dir)
+    (if file-dir
+        (substring file-dir 0 (- (length file-dir) 1))
+      ".")))
+
+(defun svn-status-get-file-list-per-directory (files)
+  ;;(message "%S" files)
+  (let ((dir-list nil)
+        (i files)
+        (j)
+        (dir))
+    (while i
+      (setq dir (svn-status-get-directory (car i)))
+      (setq j (assoc dir dir-list))
+      (if j
+          (progn
+            ;;(message "dir already present %S %s" j dir)
+            (setcdr j (append (cdr j) (list (car i)))))
+        (setq dir-list (append dir-list (list (list dir (car i))))))
+      (setq i (cdr i)))
+    ;;(message "svn-status-get-file-list-per-directory: %S" dir-list)
+    dir-list))
+
+(defun svn-status-property-ignore-file ()
+  (interactive)
+  (let ((d-list (svn-status-get-file-list-per-directory (svn-status-marked-files)))
+        (dir)
+        (f-info)
+        (ext-list))
+    (while d-list
+      (setq dir (caar d-list))
+      (setq f-info (cdar d-list))
+      (setq ext-list (mapcar '(lambda (i)
+                                (svn-status-line-info->filename-nondirectory i)) f-info))
+      ;;(message "ignore in dir %s: %S" dir f-info)
+      (save-window-excursion
+        (when (y-or-n-p (format "Ignore %S for %s? " ext-list dir))
+          (svn-status-property-edit
+           (list (svn-status-find-info-for-file-name dir)) "svn:ignore" ext-list)
+          (svn-prop-edit-do-it nil)))   ; synchronous
+      (setq d-list (cdr d-list)))
+    (svn-status-update)))
+
+(defun svn-status-property-ignore-file-extension ()
+  (interactive)
+  (let ((d-list (svn-status-get-file-list-per-directory (svn-status-marked-files)))
+        (dir)
+        (f-info)
+        (ext-list))
+    (while d-list
+      (setq dir (caar d-list))
+      (setq f-info (cdar d-list))
+      ;;(message "ignore in dir %s: %S" dir f-info)
+      (setq ext-list nil)
+      (while f-info
+        (add-to-list 'ext-list (concat "*."
+                                       (file-name-extension
+                                        (svn-status-line-info->filename (car f-info)))))
+        (setq f-info (cdr f-info)))
+      ;;(message "%S" ext-list)
+      (save-window-excursion
+        (when (y-or-n-p (format "Ignore %S for %s? " ext-list dir))
+          (svn-status-property-edit
+           (list (svn-status-find-info-for-file-name dir)) "svn:ignore"
+           ext-list)
+          (svn-prop-edit-do-it nil)))
+      (setq d-list (cdr d-list)))
+    (svn-status-update)))
+
+(defun svn-status-property-edit-svn-ignore ()
+  (interactive)
+  (let* ((line-info (svn-status-get-line-information))
+         (dir (if (svn-status-line-info->directory-p line-info)
+                  (svn-status-line-info->filename line-info)
+                (svn-status-get-directory line-info))))
+    (svn-status-property-edit
+     (list (svn-status-find-info-for-file-name dir)) "svn:ignore")
+    (message "Edit svn:ignore on %s" dir)))
+
+
+(defun svn-status-property-set-keyword-list ()
+  "Edit the svn:keywords property on the marked files."
+  (interactive)
+  ;;(message "Set svn:keywords for %S" (svn-status-marked-file-names))
+  (svn-status-property-edit (svn-status-marked-files) "svn:keywords"))
+
+(defun svn-status-property-set-eol-style ()
+  "Edit the svn:eol-style property on the marked files."
+  (interactive)
+  (svn-status-property-set-property
+   (svn-status-marked-files) "svn:eol-style"
+   (completing-read "Set svn:eol-style for the marked files: "
+                    (mapcar 'list '("native" "CRLF" "LF" "CR"))
+                    nil t)))
+
+;; --------------------------------------------------------------------------------
+;; svn-prop-edit-mode:
+;; --------------------------------------------------------------------------------
+
+(defvar svn-prop-edit-mode-map () "Keymap used in `svn-prop-edit-mode' buffers.")
+
+(when (not svn-prop-edit-mode-map)
+  (setq svn-prop-edit-mode-map (make-sparse-keymap))
+  (define-key svn-prop-edit-mode-map [(control ?c) (control ?c)] 'svn-prop-edit-done)
+  (define-key svn-prop-edit-mode-map [(control ?c) (control ?d)] 'svn-prop-edit-svn-diff)
+  (define-key svn-prop-edit-mode-map [(control ?c) (control ?s)] 'svn-prop-edit-svn-status)
+  (define-key svn-prop-edit-mode-map [(control ?c) (control ?l)] 'svn-prop-edit-svn-log)
+  (define-key svn-prop-edit-mode-map [(control ?c) (control ?q)] 'svn-prop-edit-abort))
+
+(easy-menu-define svn-prop-edit-mode-menu svn-prop-edit-mode-map
+"'svn-prop-edit-mode' menu"
+                  '("SVN-PropEdit"
+                    ["Commit" svn-prop-edit-done t]
+                    ["Show Diff" svn-prop-edit-svn-diff t]
+                    ["Show Status" svn-prop-edit-svn-status t]
+                    ["Show Log" svn-prop-edit-svn-log t]
+                    ["Abort" svn-prop-edit-abort t]))
+
+(defun svn-prop-edit-mode ()
+  "Major Mode to edit file properties of files under svn control.
+Commands:
+\\{svn-prop-edit-mode-map}"
+  (interactive)
+  (kill-all-local-variables)
+  (use-local-map svn-prop-edit-mode-map)
+  (easy-menu-add svn-prop-edit-mode-menu)
+  (setq major-mode 'svn-prop-edit-mode)
+  (setq mode-name "svn-prop-edit"))
+
+(defun svn-prop-edit-abort ()
+  (interactive)
+  (bury-buffer)
+  (set-window-configuration svn-status-pre-propedit-window-configuration))
+
+(defun svn-prop-edit-done ()
+  (interactive)
+  (svn-prop-edit-do-it t))
+
+(defun svn-prop-edit-do-it (async)
+  (message "svn propset %s on %s"
+           svn-status-propedit-property-name
+           (mapcar 'svn-status-line-info->filename svn-status-propedit-file-list))
+  (save-excursion
+    (set-buffer (get-buffer "*svn-property-edit*"))
+    (set-buffer-file-coding-system 'undecided-unix nil)
+    (setq svn-status-temp-file-to-remove
+          (concat svn-status-temp-dir "svn-prop-edit.txt" svn-temp-suffix))
+    (write-region (point-min) (point-max) svn-status-temp-file-to-remove nil 1))
+  (when svn-status-propedit-file-list ; there are files to change properties
+    (svn-status-create-arg-file svn-status-temp-arg-file ""
+                                svn-status-propedit-file-list "")
+    (setq svn-status-propedit-file-list nil)
+    (svn-run-svn async t 'propset "propset"
+         svn-status-propedit-property-name
+                 "--targets" svn-status-temp-arg-file
+                 "-F" (concat svn-status-temp-dir "svn-prop-edit.txt" svn-temp-suffix))
+    (unless async (svn-status-remove-temp-file-maybe)))
+  (set-window-configuration svn-status-pre-propedit-window-configuration))
+
+(defun svn-prop-edit-svn-diff (arg)
+  (interactive "P")
+  (set-buffer "*svn-status*")
+  (svn-status-show-svn-diff-for-marked-files arg))
+
+(defun svn-prop-edit-svn-log (arg)
+  (interactive "P")
+  (set-buffer "*svn-status*")
+  (svn-status-show-svn-log arg))
+
+(defun svn-prop-edit-svn-status ()
+  (interactive)
+  (pop-to-buffer "*svn-status*")
+  (other-window 1))
+
+;; --------------------------------------------------------------------------------
+;; svn-log-edit-mode:
+;; --------------------------------------------------------------------------------
+
+(defvar svn-log-edit-mode-map () "Keymap used in `svn-log-edit-mode' buffers.")
+
+(when (not svn-log-edit-mode-map)
+  (setq svn-log-edit-mode-map (make-sparse-keymap))
+  (define-key svn-log-edit-mode-map (kbd "C-c C-c") 'svn-log-edit-done)
+  (define-key svn-log-edit-mode-map (kbd "C-c C-d") 'svn-log-edit-svn-diff)
+  (define-key svn-log-edit-mode-map (kbd "C-c C-s") 'svn-log-edit-save-message)
+  (define-key svn-log-edit-mode-map (kbd "C-c C-i") 'svn-log-edit-svn-status)
+  (define-key svn-log-edit-mode-map (kbd "C-c C-l") 'svn-log-edit-svn-log)
+  (define-key svn-log-edit-mode-map (kbd "C-c C-?") 'svn-log-edit-show-files-to-commit)
+  (define-key svn-log-edit-mode-map (kbd "C-c C-z") 'svn-log-edit-erase-edit-buffer)
+  (define-key svn-log-edit-mode-map (kbd "C-c C-q") 'svn-log-edit-abort))
+
+(easy-menu-define svn-log-edit-mode-menu svn-log-edit-mode-map
+"'svn-log-edit-mode' menu"
+                  '("SVN-Log"
+                    ["Save to disk" svn-log-edit-save-message t]
+                    ["Commit" svn-log-edit-done t]
+                    ["Show Diff" svn-log-edit-svn-diff t]
+                    ["Show Status" svn-log-edit-svn-status t]
+                    ["Show Log" svn-log-edit-svn-log t]
+                    ["Show files to commit" svn-log-edit-show-files-to-commit t]
+                    ["Erase buffer" svn-log-edit-erase-edit-buffer]
+                    ["Abort" svn-log-edit-abort t]))
+
+(defun svn-log-edit-mode ()
+  "Major Mode to edit svn log messages.
+Commands:
+\\{svn-log-edit-mode-map}"
+  (interactive)
+  (kill-all-local-variables)
+  (use-local-map svn-log-edit-mode-map)
+  (easy-menu-add svn-log-edit-mode-menu)
+  (setq major-mode 'svn-log-edit-mode)
+  (setq mode-name "svn-log-edit")
+  (run-hooks 'svn-log-edit-mode-hook))
+
+(defun svn-log-edit-abort ()
+  (interactive)
+  (bury-buffer)
+  (set-window-configuration svn-status-pre-commit-window-configuration))
+
+(defun svn-log-edit-done ()
+  (interactive)
+  (message "svn-log editing done")
+  (save-excursion
+    (set-buffer (get-buffer "*svn-log-edit*"))
+    (set-buffer-file-coding-system 'undecided-unix nil)
+    (write-region (point-min) (point-max)
+                  (concat svn-status-temp-dir "svn-log-edit.txt" svn-temp-suffix) nil 1))
+  (when svn-status-files-to-commit ; there are files to commit
+    (svn-status-create-arg-file svn-status-temp-arg-file ""
+                                svn-status-files-to-commit "")
+    (setq svn-status-files-to-commit nil)
+    (setq svn-status-temp-file-to-remove (concat svn-status-temp-dir "svn-log-edit.txt" svn-temp-suffix))
+    (svn-run-svn t t 'commit "commit" "--targets" svn-status-temp-arg-file
+                 "-F" svn-status-temp-file-to-remove))
+  (set-window-configuration svn-status-pre-commit-window-configuration))
+
+(defun svn-log-edit-svn-diff (arg)
+  "Show the diff we are about to commit.
+If ARG then show diff between some other version of the selected files."
+  (interactive "P")
+  (set-buffer "*svn-status*")
+  (svn-status-show-svn-diff-for-marked-files arg))
+
+(defun svn-log-edit-svn-log (arg)
+  (interactive "P")
+  (set-buffer "*svn-status*")
+  (svn-status-show-svn-log arg))
+
+(defun svn-log-edit-svn-status ()
+  (interactive)
+  (pop-to-buffer "*svn-status*")
+  (other-window 1))
+
+(defun svn-log-edit-show-files-to-commit ()
+  (interactive)
+  (message "Files to commit: %S"
+           (mapcar 'svn-status-line-info->filename svn-status-files-to-commit)))
+
+(defun svn-log-edit-save-message ()
+  "Save the current log message to the file `svn-log-edit-file-name'."
+  (interactive)
+  (write-region (point-min) (point-max) svn-log-edit-file-name))
+
+(defun svn-log-edit-erase-edit-buffer ()
+  "Delete everything in the *svn-log-edit* buffer."
+  (interactive)
+  (set-buffer "*svn-log-edit*")
+  (erase-buffer))
+
+
+;; --------------------------------------------------------------------------------
+;; svn-log-view-mode:
+;; --------------------------------------------------------------------------------
+
+(defvar svn-log-view-mode-map () "Keymap used in `svn-log-view-mode' buffers.")
+
+(when (not svn-log-view-mode-map)
+  (setq svn-log-view-mode-map (make-sparse-keymap))
+  (define-key svn-log-view-mode-map (kbd "p") 'svn-log-view-prev)
+  (define-key svn-log-view-mode-map (kbd "n") 'svn-log-view-next)
+  (define-key svn-log-view-mode-map (kbd "=") 'svn-log-view-diff)
+  (define-key svn-log-view-mode-map (kbd "q") 'bury-buffer))
+(easy-menu-define svn-log-view-mode-menu svn-log-view-mode-map
+"'svn-log-view-mode' menu"
+                  '("SVN-LogView"
+                    ["Show Changeset" svn-log-view-diff t]))
+
+(defvar svn-log-view-font-lock-keywords
+  '(("^r.+" . font-lock-keyword-face)
+  "Keywords in svn-log-view-mode."))
+
+(define-derived-mode svn-log-view-mode log-view-mode "svn-log-view"
+  "Major Mode to show the output from svn log.
+Commands:
+\\{svn-log-view-mode-map}
+"
+  (use-local-map svn-log-view-mode-map)
+  (easy-menu-add svn-log-view-mode-menu)
+  (set (make-local-variable 'font-lock-defaults) '(svn-log-view-font-lock-keywords t)))
+
+(defun svn-log-view-next ()
+  (interactive)
+  (when (re-search-forward "^r[0-9]+" nil t)
+    (beginning-of-line 3)))
+
+(defun svn-log-view-prev ()
+  (interactive)
+  (when (re-search-backward "^r[0-9]+" nil t 2)
+    (beginning-of-line 3)))
+
+(defun svn-log-revision-at-point ()
+  (save-excursion
+    (re-search-backward "^r\\([0-9]+\\)")
+    (match-string-no-properties 1)))
+
+(defun svn-log-view-diff (arg)
+  "Show the changeset for a given log entry.
+When called with a prefix argument, ask the user for the revision."
+  (interactive "P")
+  (let* ((upper-rev (svn-log-revision-at-point))
+        (lower-rev (number-to-string (- (string-to-number upper-rev) 1)))
+        (rev-arg (concat lower-rev ":" upper-rev)))
+    (when arg
+      (setq rev-arg (read-string "Revision for changeset: " rev-arg)))
+    (svn-run-svn nil t 'diff "diff" (concat "-r" rev-arg))
+    (svn-status-show-process-buffer-internal t)
+    (save-excursion
+      (set-buffer "*svn-process*")
+      (diff-mode)
+      (font-lock-fontify-buffer))))
+
+(provide 'psvn)
+
+;;; psvn.el ends here