changeset 10219:d97313bb6f39

(bibtex-string, bibtex-preamble): Use forward-line. (sort-subr): Don't call autload for this--that's done in loaddefs.el. (bibtex-mode): Add autoload cookie. Changed keybinding for bibtex-print-help-message (from \C-ch to \C-c?). Therefore, describe-mode is not longer on \C-c?. Also, changed prefix \C-cn for bibtex-narrow functions to \C-c\C-r. (bibtex-string-files): Changed documentation. (bibtex-mode-map): Inscriptions of menu bar changed from "Entry Types" to "Entry-Types" and "Bibtex Edit" to "BibTeX-Edit". (bibtex-string-files): Changed documentation. (bibtex-mode): If environment variable BIBINPUTS isn't defined, string files are searched in the current directory. (bibtex-completion-candidates): Now buffer-local to allow evaluation of different bibtex-string-files in different buffers. (bibtex-autokey-edit-before-use, bibtex-clean-entry): New variable that determines, if the user is allowed to edit auto-generated reference keys before they are used. (bibtex-generate-autokey, bibtex-clean-entry): New function to generate an autokey if necessary. (bibtex-autokey-names, bibtex-autokey-name-change-strings, bibtex-autokey-name-length, bibtex-autokey-name-separator, bibtex-autokey-year-length, bibtex-autokey-titlewords, bibtex-autokey-title-terminators, bibtex-autokey-titlewords-stretch, bibtex-autokey-titleword-first-ignore, 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): New variables related to bibtex-generate-autokey. (bibtex-find-entry-location): Optional second parameter maybedup to tell it that entering a duplicate entry isn't to report by an error but by the return value of the function (necessary for bibtex-clean-entry to find the correct position of an entry with an autogenerated key without disturbing the user with unwanted messages). (bibtex-help-message): New variable to avoid printing of help messages in the echo area. (assoc-of-regexp): New function to match an alist of regexps. (bibtex-string-files, bibtex-completion-candidates, bibtex-mode): New variables to allow bibtex-complete-string to work on strings initialized from a variable and from @String definitions in a list of files, too. (bibtex-predefined-strings, bibtex-entry-field-alist): Changed to user options. (bibtex-mode): Changed doc string. (many functions and variables): Changed documentation strings of variables and functions to hold a complete sentence in the first line. (bibtex-print-help-message): Now line dependent and reports if it is called outside a BibTeX field. (validate-bibtex-buffer): Completely rewritten to validate, if buffer is syntactically correct. (find-bibtex-duplicates): Moved into validate-bibtex-buffer. (ispell-abstract, bibtex-ispell-abstract, ispell-bibtex-entry, bibtex-ispell-entry, beginning-of-bibtex-entry, bibtex-beginning-of-entry, end-of-bibtex-entry, bibtex-end-of-entry, hide-bibtex-entry-bodies, bibtex-hide-entry-bodies, narrow-to-bibtex-entry, bibtex-narrow-to-entry, sort-bibtex-entries, bibtex-sort-entries, validate-bibtex-buffer, bibtex-validate-buffer, find-bibtex-entry-location, bibtex-find-entry-location): All interactive functions are renamed, so that any interface function begins with "bibtex-". Mapping: ispell-abstract --> bibtex-ispell-abstract ispell-bibtex-entry --> bibtex-ispell-entry beginning-of-bibtex-entry --> bibtex-beginning-of-entry end-of-bibtex-entry --> bibtex-end-of-entry hide-bibtex-entry-bodies --> bibtex-hide-entry-bodies narrow-to-bibtex-entry --> bibtex-narrow-to-entry sort-bibtex-entries --> bibtex-sort-entries validate-bibtex-buffer --> bibtex-validate-buffer find-bibtex-entry-location --> bibtex-find-entry-location (bibtex-maintain-sorted-entries, bibtex-sort-ignore-string-entries): Default is now t. (bibtex-complete-string): String list is built from additional string list bibtex-predefined-string and current strings in file. (string-equalp): Deleted and substituted by string-equal. (assoc-string-equalp): Renamed to assoc-ignore-case. (bibtex-entry): Reference key can be entered with completion. All reference keys that are defined in buffer and all labels that appear in crossreference entries are object to completion. (Entry types): Changed order of entries in menu "entry types". (bibtex-entry-field-alist): Changed order of entries slightly to be more conform with standard BibTeX style layouts. (bibtex-mode-map): Uniform keybindings for \C-c\C-e prefix (often used types on control keys, sometimes used types on normal keys, rarely used types on shift keys, almost never used types on meta keys). (bibtex-mode-map): Function narrow-to-bibtex-entry and counterpart widen and function hide-bibtex-entry-bodies and counterpart show-all bounded to appropriate local keys. (bibtex-abbrev-table): Deleted (bibtex-current-entry-label, put-string-on-kill-ring): Deleted (AUCTeX provides all the functionality needed for citation completion). (bibtex-enclosing-reference, bibtex-pop-previous, bibtex-pop-next, bibtex-clean-entry): Hacked for speed (bibtex-pop-previous and bibtex-pop-next were to slow for larger BibTeX files). (bibtex-pop-previous, bibtex-pop-next): Delimiters from previous or next entry are changed to actual delimters if necessary. (bibtex-entry): Fixed bug (False entry wasn't reported in error message if bibtex-entry was called with undefined reference name). (bibtex-entry-field-alist, bibtex-entry, bibtex-make-field, bibtex-next-field, bibtex-clean-entry): Every reference entry now contains a comment in addition to the name of the reference. This comment appears in the echo area if you start editing that field (after calling bibtex-next-field). (bibtex-include-OPTcrossref, bibtex-entry): Changed bibtex-include-OPTcrossref from single boolean variable to hold a list of reference names which should have a crossref field. (bibtex-complete-word): New function, which completes word fragment before point to the longest prefix of predefined strings in the buffer in the same way that ispell-complete-word operates for words found in the dictionary. (bibtex-reference-head): Start of bibtex-reference-head changed from "^[ \t]*\\(" to "^\\( \\|\t\\)*\\(" (bibtex-pop-previous and bibtex-pop-next didn't work, probably due to a bug in re-search-forward). (several functions): Added support for {} as field delimiters (better than '"' for accented characters. (bibtex-clean-entry): If optional field crossref is empty or missing, former optional fields (if bibtex-include-OPTcrossref was t) are necessary again. bibtex-clean-entry complains if they are empty but not if they are missing, so you can intenionally omit them, e. g. for a pseudo @Journal entry (needed for crossreferences) made out of an @article with missing non-optional fields. Menu bar entries aren't centered anymore.
author Richard M. Stallman <rms@gnu.org>
date Fri, 23 Dec 1994 04:18:29 +0000
parents b78b8c445f33
children 126f7560fd28
files lisp/textmodes/bibtex.el
diffstat 1 files changed, 1756 insertions(+), 1230 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/textmodes/bibtex.el	Fri Dec 23 03:30:53 1994 +0000
+++ b/lisp/textmodes/bibtex.el	Fri Dec 23 04:18:29 1994 +0000
@@ -2,14 +2,14 @@
 
 ;; Copyright (C) 1992, 1994 Free Software Foundation, Inc.
 
-;; Author: Bengt Martensson <ubrinf!mond!bengt>
+;; Author: Stefan Schoef <schoef@informatik.uni-oldenburg.de>
+;;      Bengt Martensson <ubrinf!mond!bengt>
 ;;	Mark Shapiro <shapiro@corto.inria.fr>
 ;;	Mike Newton <newton@gumby.cs.caltech.edu>
 ;;	Aaron Larson <alarson@src.honeywell.com>
-;; Version: 1.3.1
-;; Maintainer:Aaron Larson <alarson@src.honeywell.com>
-;; Adapted-By: ESR
-;; Keywords: tex, bib
+;; Version: 2.0  (based on RCS $Revision: 1.22 $, $Date: 1994/12/21 15:02:30 $)
+;; Maintainer: Stefan Schoef <schoef@informatik.uni-oldenburg.de>
+;; Keywords: BibTeX, LaTeX, TeX
 
 ;; This file is part of GNU Emacs.
 
@@ -27,245 +27,379 @@
 ;; along with GNU Emacs; see the file COPYING.  If not, write to
 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 
-;;; TODO distribute texinfo file.
-
-;;; LCD Archive Entry:
-;;; bibtex-mode|Bengt Martensson, Marc Shapiro, Aaron Larson|
-;;; alarson@src.honeywell.com|
-;;; Support for maintaining BibTeX format bibliography databases|
-;;; 93-03-29|version 1.3|~/modes/bibtex-mode.el.Z|
-
-;;; Commentary:
-
-;;; BUGS:
-;;;   1. using regular expressions to match the entire bibtex entry dies
-;;;      on long bibtex entires (e.g. those containing abstracts) since
-;;;      the length of regular expression matches is fairly limited.
-;;;   2. When inserting a string (with \C-C\C-E\s) hitting a TAB results
-;;;      in the error message "Can't find enclosing Bibtex field" instead
-;;;      of moving to the empty string. [reported by gernot@cs.unsw.oz.au]
-;;;   3. Function string-equalp should be in a library file, not in this
-;;;      file. 
-
-;;; (current keeper: alarson@src.honeywell.com
-;;;  previous: shapiro@corto.inria.fr)
-
-;;; Change Log:
-
-;; Mon Mar 29 14:06:06 1993  Aaron Larson  (alarson at gendibal)
-;;
-;;	* bibtex.el: V1.3 released Mar 30, 1993
-;;	(bibtex-field-name):  Fix to match definition if latex manual,
-;;	specifically letters, digits, and punctuation other than comma.
-;;	Underscore is retained for historical reasons. 
-;;	(bibtex-make-field):  Fix to work around bug in Lucid prin1-to-string
-;;	function as reported by Martin Sjolin <marsj@ida.liu.se>. 
-;;	(bibtex-entry):  minor code cleanup.
-;;	(bibtex-mode-map): Remove key binding (C-c n) for
-;;	narrow-to-bibtex-entry, previous binding violated emacs policy of
-;;	reserving C-c followed by a letter for user customization.
-;;	revise modification history to better conform to FSF changelog
-;;	standards.
-;;	(bibtex-refile-entry): Removed.  Would need disclaimer papers to
-;;	incorporate it into official sources, and unable to contact author.
-;;	Fix minor "syntax" errors in documentation strings and such found
-;;	by new byte compiler.  Funs bibtex-mode, bibtex-remove-double-quotes
-;;
-;;
-;; Fri Jan 15 14:06:06 1993  Aaron Larson  (alarson at gendibal)
-;;
-;;	* bibtex.el: V1.2 released Feb 15 1993
-;;	(find-bibtex-entry-location bibtex-make-field): Fixed placement of
-;;	"interactive specification".  [Bug report from
-;;	mernst@theory.lcs.mit.edu] 
-;;	Fixed problem where bibtex-entry would fail if user typed entry
-;;	name in wrong case.
-;;	(bibtex-inside-field) Position the cursor _before_ the last comma
-;;	on a line (the comma is not necessarily "inside" the field); this
-;;	does not seem to break any existing code. ref sct@dcs.edinburgh.ac.uk
-;;	(bibtex-enclosing-field, bibtex-enclosing-reference): leave
-;;	point unmoved if no enclosing field/reference is found.  As a
-;;	result of changes (3) and (4) bibtex-next-field works properly,
-;;	even when called from the entry key position. 
-;;	(bibtex-remove-OPT): realign the '=' after removing the 'opt'.
-;;	(bibtex-clean-entry): always remove any trailing comma from the
-;;	end of a bibtex entry (these commas get stripped automatically when
-;;	optional fields are killed by bibtex-kill-optional-field, but can be
-;;	left if optional fields are removed by other means).
-;;	(bibtex-x-help) Replace tab with spaces in X menu as noted by
-;;	khera@cs.duke.edu
-;;	(bibtex-refile-entry): Added (from brannon@jove.cs.caltech.edu)
-;;	(bibtex-sort-ignore-string-entries sort-bibtex-entries,
-;;	map-bibtex-entries): Added variable as requested by  
-;;	gernot@cs.unsw.oz.au, required changes to funs.
-;;	(bibtex-current-entry-label): Added at request of
-;;	yasuro@maekawa.is.uec.ac.jp
-;;	(bibtex-DEAthesis:) Deleted along with corresponding entry from
-;;	bibtex-x-help  per shapiro@corto.inria.fr 
-;;	Moved narrow-to-bibtex-entry from C-c C-n to C-c n (the previous
-;;	binding was in conflict with the binding for bibtex-pop-next.
-;;	bug report from [shapiro@corto.inria.fr]
-;;
+;;; TODO:
+;;  Distribute texinfo file.
+;;  A better concept for intermixing quote and brace delimiters is
+;;  needed.
 
-;;; 
-;;; alarson@src.honeywell.com 92-Feb-13
-;;;   1. Made bibtex-entry user callable, now prompts for entry type (e.g.
-;;;      Article), with completion, and bound it to a key.  This is now my
-;;;      preferred way to add most entries. 
-;;;   2. Made fields of a bibtex entry derived from the alist bibtex-entry-
-;;;      field-alist.
-;;;   3. Fixed handling of escaped double quotes, e.g. "Schr{\"o}dinger".
-;;;   4. Fixed bug where unhiding bibtex entries moved point.
-;;;   5. Made "field name" specs permit (name . value) for defaulting.  E.g. 
-;;;       (setq bibtex-mode-user-optional-fields '(("library" . "alarson")))
-;;;      will generate the field:
-;;;       library	= "alarson",
-;;;   6. Added binding for narrow-to-bibtex-entry
-;;;   7. Adding a bibtex entry now runs hook: bibtex-add-entry-hook
-;;;   8. Made bibtex-clean-entry fixup text alignment, and eliminated the
-;;;      dependency on bibtex-enclosing-reference which has a problem with
-;;;      long entries (e.g. those containing abstracts).
-;;; 
-;;; alarson@src.honeywell.com 92-Jan-31
-;;;   Added support for: ispell, beginning/end of entry movement, a simple
-;;;   outline like mode (hide the bodies of bibtex entries), support for
-;;;   sorting bibtex entries, and maintaining them in sorted order, and
-;;;   simple buffer validation.
-;;;   User visible functions added:
-;;;      ispell-{abstract,bibtex-entry}, {beginning,end}-of-bibtex-entry
-;;;      hide-bibtex-entry-bodies, sort-bibtex-entries, validate-bibtex-
-;;;      buffer, find-bibtex-duplicates
-;;;   user visible variables added:
-;;; 	 bibtex-maintain-sorted-entries
-;;;   new local keybindings:
-;;; 	C-c$   ispell-bibtex-entry
-;;; 	M-C-a  beginning-of-bibtex-entry
-;;; 	M-C-e  end-of-bibtex-entry
-;;; Mike Newton (newton@gumby.cs.caltech.edu) 90.11.17
-;;;  * Handle items like
-;;;          title = poft # "Fifth Tri-quarterly" # random-conf,
-;;;    and   title = {This title is inside curlies}
-;;;  * added user settable, always present, optional fields
-;;;  * fixed 'bibtex-find-it's doc string's location
-;;;  * bibtex-field-text made more general (it wouldn't handle the # construct)
-;;;		and it now handles a small subset of the {} cases
+;;; PURPOSE:
+;;  Major mode for editing and validating BibTeX files.
 
-;;; Bengt Martensson, March 6
-;;;   Adapted to Bibtex 0.99 by updating the optional fields according
-;;;   to the document BibTeXing, Oren Patashnik, dated January 31, 1988.
-;;;   Updated documentation strings accordingly.  Added (provide 'bibtex).
-;;;   If bibtex-include-OPT-crossref is non-nil, every entry will have
-;;;   an OPTcrossref field, analogously for bibtex-include-OPTkey and
-;;;   bibtex-include-OPTannote.  Added bibtex-preamble, bound to ^C^EP,
-;;;   and also found in X- and sun-menus.  Cleaned up the sun-menu
-;;;   stuff, and made it more uniform with the X-menu stuff.  Marc: I
-;;;   strongly suspect that I broke your parsing...  (Or, more
-;;;   correctly, BibTeX 0.99 broke it.)
-;;;   Added bibtex-clean-entry-zap-empty-opts, defvar'd to t.  If it
-;;;   is nil, bibtex-clean-entry will leave empty optional fields alone.
-
-;;; Marc Shapiro 1-feb-89: integrated changes by Bengt Martensson 88-05-06:
-;;;   Added Sun menu support.  Locally bound to right mouse button in 
-;;;   bibtex-mode.  Emacs 18.49 allows local mouse bindings!!
-;;;   Commented out DEAthesis.
 
-;;; Marc Shapiro 6-oct-88
-;;;  * skip-whitespace replaced by skip-chars-forward
-;;;  * use indent-to-column instead of inserting tabs (changes to 
-;;;    bibtex-entry, bibtex-make-entry, bibtex-make-OPT-entry, renamed to
-;;;    bibtex-make-optional-entry)
-;;;  * C-c C-k deletes the current OPT entry entirely
-;;;  * C-c C-d replaces text of field with ""
-;;;  * renamed bibtex-find-it to bibtex-find-text.  With arg, now goes to
-;;;    start of text.  Fixed bugs in it.
-
-;;; Marc Shapiro 23-sep-88
-;;;  * bibtex-clean-entry moves past end of entry.
-;;;  * bibtex-clean-entry signals mandatory fields left empty.
-
-;;; Marc Shapiro 18-jul-88
-;;;  * Fixed bug in bibtex-flash-entry
-;;;  * Moved all the entry type keystrokes to "C-c C-e something" (instead of
-;;;    "C-c something" previously) to make room for more.  C-c C-e is
-;;;    supposed to stand for "entry" [idea taken from mail-mode].  Moved
-;;;    bibtex-pop-previous to C-c C-p and bibtex-pop-next to C-c C-n.
-;;;  * removed binding for "\e[25~"
-;;;  * replaced bibtex-clean-optionals by bibtex-clean-entry, bound to
-;;;    C-c C-c
-
-;;; Marc Shapiro 13-jul-88 [based on ideas by Sacha Krakowiak of IMAG]
-;;;  * bibtex-pop-previous replaces current field with value of
-;;;    similar field in previous entry.  May be called n times in a row
-;;;    (or with arg n) to pop similar field of n'th previous entry.
-;;;    There is also a bibtex-pop-next to get similar field of next
-;;;    entry.
-;;;  * C-c C-k now kills all empty optional fields of current entry, and
-;;;    removes "OPT" for those optional fields which have text. 
-
-;;; Marc Shapiro 14-dec-87
-;;;   Cosmetic fixes.  Fixed small bug in bibtex-move-outside-of-entry.
-;;; Skip Montanaro <steinmetz!sprite!montanaro> 7-dec-87, Shapiro 10-dec-87
-;;;   before inserting an entry, make sure we are outside of a bib entry
-;;; Marc Shapiro 3-nov-87
-;;;   addition for France: DEAthesis
-;;; Marc Shapiro 19-oct-1987
-;;;   add X window menu option; bug fixes. TAB, LFD, C-c " and C-c C-o now
-;;;   behave consistently; deletion never occurs blindly.
-;;; Marc Shapiro <shapiro@inria.inria.fr> 15-oct-1986
-;;;    align long lines nicely; C-c C-o checks for the "OPT" string;
-;;;    TAB goes to the end of the string; use lower case; use
-;;;    run-hooks
-
-;;; Bengt Martensson <ubrinf!mond!bengt> 87-06-28
-;;; Bengt Martensson <bengt@mathematik.uni-Bremen.de> 87-06-28
-;;;   Original version
-
-;;; Code:
-
-;;; NOTE by Marc Shapiro, 14-dec-87:
-;;; (bibtex-x-environment) binds an X menu for bibtex mode to x-button-c-right.
-;;; Trouble is, in Emacs 18.44 you can't have a mode-specific mouse binding,
-;;; so it will remain active in all windows.  Yuck!
-
-(provide 'bibtex)
-
-;;; these guys typically don't have autoloads...[alarson:19920131.1548CST]
-;;; Check for fboundp first so that if user autoloads them from non standard 
-;;; places, the users bindings will take precedence.
-(if (not (fboundp 'sort-subr))
-    (autoload 'sort-subr "sort"))
-
-;;; These should be in a more generally accessible location. 
-
-(defun string-equalp (s1 s2)
-  "Like string= except differences in case are ignored."
-  (let ((ss1 (if (symbolp s1) (symbol-name s1) s1))
-	(ss2 (if (symbolp s2) (symbol-name s2) s2)))
-    (and (= (length ss1) (length ss2))
-	 (string-equal (upcase ss1) (upcase ss2)))))
+;;; USAGE:
+;;  See documentation for function bibtex-mode (or type "\M-x describe-mode"
+;;  when you are in bibtex-mode).
 
 
+;;; KNOWN BUGS:
+;;   1. using regular expressions to match the entire BibTeX entry dies
+;;      on long entries (e.g. those containing abstracts) since
+;;      the length of regular expression matches is fairly limited.
+;;   2. Calling bibtex-find-text in a string entry results in the
+;;      error message "Can't find enclosing Bibtex field" instead of
+;;      moving to the empty string. [reported by gernot@cs.unsw.oz.au]
 
+;;; (current keeper: schoef@informatik.uni-oldenburg.de
+;;;  previous: alarson@src.honeywell.com)
+
+;;; USER OPTIONS:
+
+(defvar bibtex-field-left-delimiter "{"
+  "*Set this to { or \" according to your personal preferences.")
+
+(defvar bibtex-field-right-delimiter "}"
+  "*Set this to } or \" according to your personal preferences.")
+
+(defvar bibtex-include-OPTcrossref '("InProceedings" "InCollection")
+  "*All entries listed here will have an OPTcrossref field.")
+
+(defvar bibtex-include-OPTkey t
+  "*If non-nil, all entries will have an OPTkey field.")
+
+(defvar bibtex-include-OPTannote t
+  "*If non-nil, all entries will have an OPTannote field.")
+
+(defvar bibtex-mode-user-optional-fields nil
+  "*List of optional fields the user wants to have always present.
+Entries should be lists of strings with two elements (first element =
+name of the field, second element = comment to appear in the echo area).")
 
 (defvar bibtex-clean-entry-zap-empty-opts t
   "*If non-nil, bibtex-clean-entry will delete all empty optional fields.")
 
-(defvar bibtex-include-OPTcrossref t
-  "*If non-nil, all entries will have an OPTcrossref field.")
-(defvar bibtex-include-OPTkey t
-  "*If non-nil, all entries will have an OPTkey field.")
-(defvar bibtex-include-OPTannote t
-  "*If non-nil, all entries will have an OPTannote field.")
+(defvar bibtex-sort-ignore-string-entries t
+  "*If true, 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.).")
+
+(defvar bibtex-maintain-sorted-entries t
+  "*If true, 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) from bibtex-mode.")
+
+(defvar bibtex-entry-field-alist
+  '(
+    ("Article" . (((("author" "Author1 [and Author2 ...] [and others]")
+                    ("title" "Title of the article (will be converted 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")
+                    ("month" "Month of the publication as a string (remove braces)")
+                    ("pages" "Pages in the journal")
+                    ("note" "Remarks to be put at the end of the \\bibitem")))
+		  ((("author" "Author1 [and Author2 ...] [and others]")
+                    ("title" "Title of the article (will be converted 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")
+		    ("month" "Month of the publication as a string (remove braces)")
+                    ("pages" "Pages in the journal")
+                    ("note" "Remarks to be put at the end of the \\bibitem")))))
+    ("Book" . (((("author" "Author1 [and Author2 ...] [and others]")
+                 ("title" "Title 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")
+                 ("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 (will be converted to lowercase)"))
+		   (("author" "Author1 [and Author2 ...] [and others]")
+                    ("howpublished" "The way in which the booklet was published")
+                    ("address" "Address of the publisher")
+                    ("year" "Year of publication")
+                    ("month" "Month of the publication as a string (remove braces)")
+                    ("note" "Remarks to be put at the end of the \\bibitem")))))
+    ("InBook" . (((("author" "Author1 [and Author2 ...] [and others]")
+                   ("title" "Title of the book")
+                   ("chapter" "Chapter 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")
+                   ("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")
+                   ("type" "Word to use instead of \"chapter\"")
+                   ("note" "Remarks to be put at the end of the \\bibitem")))
+		 ((("author" "Author1 [and Author2 ...] [and others]")
+                   ("title" "Title of the book")
+                   ("chapter" "Chapter 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")
+                   ("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")
+                   ("type" "Word to use instead of \"chapter\"")
+                   ("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 (will be converted 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")
+                         ("chapter" "Chapter in the book")
+                         ("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]")
+                         ("title" "Title of the article in book (will be converted 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")
+                         ("chapter" "Chapter in the book")
+                         ("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")))))
+    ("InProceedings" . (((("author" "Author1 [and Author2 ...] [and others]")
+                          ("title" "Title of the article in proceedings (will be converted 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")
+			  ("organization" "Sponsoring organization of the conference")
+                          ("publisher" "Publishing company, its location")
+                          ("address" "Location of the Proceedings")
+                          ("month" "Month of the publication as a string (remove braces)")
+                          ("pages" "Pages in the conference proceedings")
+                          ("note" "Remarks to be put at the end of the \\bibitem")))
+			((("author" "Author1 [and Author2 ...] [and others]")
+                          ("title" "Title of the article in proceedings (will be converted to lowercase)")
+			  ("booktitle" "Name of the conference proceedings"))
+			 (("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")
+                          ("year" "Year of publication")
+			  ("organization" "Sponsoring organization of the conference")
+                          ("publisher" "Publishing company, its location")
+                          ("address" "Location of the Proceedings")
+                          ("month" "Month of the publication as a string (remove braces)")
+                          ("pages" "Pages in the conference proceedings")
+                          ("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")
+                   ("year" "Year of publication")
+		   ("month" "Month of the publication as a string (remove braces)")
+                   ("note" "Remarks to be put at the end of the \\bibitem")))))
 
-;; note: the user should be allowed to have their own list of always
-;;       available optional fields.  exs: "keywords" "categories"
+    ("MastersThesis" . (((("author" "Author1 [and Author2 ...] [and others]")
+                          ("title" "Title of the master\'s thesis (will be converted to lowercase)")
+                          ("school" "School where the master\'s thesis was written")
+                          ("year" "Year of publication"))
+			 (("address" "Address of the school (if not part of field \"school\") or country")
+                          ("type" "Type of the master\'s thesis")
+                          ("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 reference (will be converted to lowercase)")
+                 ("howpublished" "The way in which the reference was published")
+                 ("year" "Year of publication")
+                 ("month" "Month of the publication as a string (remove braces)")
+                 ("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"))
+		     (("address" "Address of the school (if not part of field \"school\") or country")
+                      ("type" "Type of the PhD. thesis")
+                      ("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"))
+		       (("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")
+                        ("publisher" "Publishing company, its location")
+			("organization" "Sponsoring organization of the conference")
+                        ("address" "Location of the Proceedings")
+                        ("month" "Month of the publication as a string (remove braces)")
+                        ("note" "Remarks to be put at the end of the \\bibitem")))))
+    ("TechReport" . (((("author" "Author1 [and Author2 ...] [and others]")
+                       ("title" "Title of the technical report (will be converted 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 reference (will be converted to lowercase)")
+                        ("note" "Remarks to be put at the end of the \\bibitem"))
+		       (("year" "Year of publication")
+                        ("month" "Month of the publication as a string (remove braces)")))))
+    )
+
+  "Defines reference 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 to be used.
+If not, the second pair is to be 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 strings with two elements
+(first element  = name of the field, 
+ second element = comment to appear in the echo area).")
+
+(defvar bibtex-predefined-strings
+  '(
+    ("jan") ("feb") ("mar") ("apr") ("may") ("jun") ("jul") ("aug")
+    ("sep") ("oct") ("nov") ("dec")
+    ("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.")
+
+(defvar bibtex-string-files nil
+  "*List of BibTeX files containing string definitions.
+Those files must be specified using pathnames relative to the
+directories specified in $BIBINPUTS. This variable is only evaluated
+when bibtex-mode is entered (i. e. when loading the BibTeX file).")
+
+(defvar bibtex-help-message t
+  "*If not nil print help messages in the echo area on entering a new field.")
 
-(defvar bibtex-mode-user-optional-fields nil		;no default value
-  "*List of optional fields that user want to have as always present 
-when making a bibtex entry.  One possibility is for ``keywords''.  
-Entries can be either strings or conses, in which case the car should be 
-string and the cdr the value to be inserted.")
+(defvar bibtex-autokey-names 1
+  "*Number of names to use for the automatically generated reference key.
+If this is set to anything but a number, all names are used.
+See the documentation of function bibtex-generate-autokey for further detail.")
+
+(defvar bibtex-autokey-name-change-strings
+  '(("\\\\\\\"a" "ae") ("\\\\\\\"o" "oe") ("\\\\\\\"u" "ue")
+    ("\\\\\\\"s" "ss")
+    ("\\\\\\\"A" "Ae") ("\\\\\\\"O" "Oe") ("\\\\\\\"U" "Ue")
+    ("{" "") ("}" ""))
+  "Alist of (old-regexp new-string) pairs.
+Any part of name matching a old-regexp is replaced by new-string.
+Case of the old-regexp is significant. All regexps are tried in the
+order in which they appear in the list, so be sure to avoid recursion here.
+See the documentation of function bibtex-generate-autokey for further detail.")
+
+(defvar 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 further detail.")
+
+(defvar bibtex-autokey-name-separator ""
+  "*String that comes between any two names in the key.
+See the documentation of function bibtex-generate-autokey for further detail.")
+
+(defvar bibtex-autokey-year-length 2
+  "*Number of rightmost digits from the year field yo incorporate into key.
+See the documentation of function bibtex-generate-autokey for further detail.")
+
+(defvar 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.
+See the documentation of function bibtex-generate-autokey for further detail.")
+
+(defvar 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 further detail.")
+
+(defvar 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 further detail.")
 
+(defvar bibtex-autokey-titleword-first-ignore
+  '("a" "an" "on" "the" "eine?" "der" "die" "das")
+  "*Determines words that may begin a title but are not to be used in the key.
+Each item of the list is a regexp. If the first word of the title matchs a
+regexp from that list, it is not included in the title, even if it is
+capitalized. Regexps in the list must be entered using lowercase letters.")
+
+(defvar bibtex-autokey-titleword-abbrevs nil
+  "*Determines exceptions to the usual abbreviation mechanism.
+A list of (old-regexp new-string) pairs. 
+Use all lowercase letters for old-regexp.
+See the documentation of function bibtex-generate-autokey for further detail.")
+
+(defvar bibtex-autokey-titleword-change-strings
+  '(("\\\\\\\"a" "ae") ("\\\\\\\"o" "oe") ("\\\\\\\"u" "ue")
+    ("\\\\\\\"s" "ss")
+    ("\\\\\\\"A" "Ae") ("\\\\\\\"O" "Oe") ("\\\\\\\"U" "Ue")
+    ("{" "") ("}" ""))
+  "Alist of (old-regexp new-string) pairs.
+Any part of title word matching a old-regexp is replaced by new-string.
+Case of the old-regexp is significant.
+See the documentation of function bibtex-generate-autokey for further detail.")
+
+(defvar 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 further detail.")
+
+(defvar bibtex-autokey-titleword-separator "_"
+  "*String to be put between the title words.
+See the documentation of function bibtex-generate-autokey for further detail.")
+
+(defvar 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 further detail.")
+
+(defvar 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 further detail.")
+
+(defvar bibtex-autokey-edit-before-use t
+  "*If non-nil, user is allowed to edit the generated key before it is used.")
+
+
+
+;;; SYNTAX TABLE, KEYBINDINGS and BIBTEX-ENTRY-LIST
 (defvar bibtex-mode-syntax-table
   (let ((st (make-syntax-table)))
     ;; [alarson:19920214.1004CST] make double quote a string quote
@@ -280,455 +414,284 @@
     (modify-syntax-entry ?~ " " st)
     st))
 
-(defvar bibtex-mode-abbrev-table nil "")
-(define-abbrev-table 'bibtex-mode-abbrev-table ())
 (defvar bibtex-mode-map
   (let ((km (make-sparse-keymap)))
     
     (define-key km "\t" 'bibtex-find-text)
     (define-key km "\n" 'bibtex-next-field)
-    (define-key km "\C-c\"" 'bibtex-remove-double-quotes)
+    (define-key km "\M-\t" 'bibtex-complete-string)
+    (define-key km "\C-c\"" 'bibtex-remove-double-quotes-or-braces)
+    (define-key km "\C-c{" 'bibtex-remove-double-quotes-or-braces)
+    (define-key km "\C-c}" 'bibtex-remove-double-quotes-or-braces)
     (define-key km "\C-c\C-c" 'bibtex-clean-entry)
-    (define-key km "\C-c?" 'describe-mode)
+    (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-optional-field)
     (define-key km "\C-c\C-d" 'bibtex-empty-field)
-
-    ;; [alarson:19920131.1543CST]
-    (define-key km "\C-c$"   'ispell-bibtex-entry)
-    (define-key km "\M-\C-a"   'beginning-of-bibtex-entry)
-    (define-key km "\M-\C-e"   'end-of-bibtex-entry)
+    (define-key km "\C-c$"   'bibtex-ispell-entry)
+    (define-key km "\M-\C-a"   'bibtex-beginning-of-entry)
+    (define-key km "\M-\C-e"   'bibtex-end-of-entry)
     (define-key km "\C-c\C-b"   'bibtex-entry)
-;    (define-key km "\C-cn" 'narrow-to-bibtex-entry)
+    (define-key km "\C-c\C-q" 'bibtex-hide-entry-bodies)
+    (define-key km "\C-c\C-a" 'show-all)
+    (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)
 
+    (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-Book)
-;    (define-key km "\C-c\C-e\C-d" 'bibtex-DEAthesis)
-    (define-key km "\C-c\C-e\C-c" 'bibtex-InProceedings)
-    (define-key km "\C-c\C-e\C-i" 'bibtex-InBook)
-    (define-key km "\C-c\C-ei" 'bibtex-InCollection)
-    (define-key km "\C-c\C-eI" 'bibtex-InProceedings)
+    (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-o" 'bibtex-remove-OPT)
-    (define-key km "\C-c\C-e\C-p" 'bibtex-PhdThesis)
+    (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-preamble)
+    (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-s" 'bibtex-string)
     (define-key km "\C-c\C-e\C-u" 'bibtex-Unpublished)
     km))
 
-(defvar bibtex-pop-previous-search-point nil
-  "Next point where bibtex-pop-previous should start looking for a similar
-entry.")
-
-(defvar bibtex-pop-next-search-point nil
-  "Next point where bibtex-pop-next should start looking for a similar
-entry.")
+(define-key bibtex-mode-map [menu-bar move/edit]
+  (cons "BibTeX-Edit" (make-sparse-keymap "BibTeX-Edit")))
+(define-key bibtex-mode-map [menu-bar move/edit bibtex-print-help-message]
+  '("Help about current field" . bibtex-print-help-message))
+(define-key bibtex-mode-map [menu-bar move/edit bibtex-complete-string]
+  '("String Complete" . bibtex-complete-string))
+(define-key bibtex-mode-map [menu-bar move/edit bibtex-next-field]
+  '("Next Field" . bibtex-next-field))
+(define-key bibtex-mode-map [menu-bar move/edit bibtex-find-text]
+  '("End of Field" . bibtex-find-text))
+(define-key bibtex-mode-map [menu-bar move/edit bibtex-pop-previous]
+  '("Snatch from Similar Preceding Field" . bibtex-pop-previous))
+(define-key bibtex-mode-map [menu-bar move/edit bibtex-pop-next]
+  '("Snatch from Similar Following Field" . bibtex-pop-next))
+(define-key bibtex-mode-map [menu-bar move/edit bibtex-remove-OPT]
+  '("Remove OPT" . bibtex-remove-OPT))
+(define-key bibtex-mode-map [menu-bar move/edit bibtex-remove-double-quotes-or-braces]
+  '("Remove Quotes or Braces" . bibtex-remove-double-quotes-or-braces))
+(define-key bibtex-mode-map [menu-bar move/edit bibtex-clean-entry]
+  '("Clean up Entry" . bibtex-clean-entry))
+(define-key bibtex-mode-map [menu-bar move/edit bibtex-sort-entries]
+  '("Sort Entries" . bibtex-sort-entries))
+(define-key bibtex-mode-map [menu-bar move/edit bibtex-validate-buffer]
+  '("Validate Entries" . bibtex-validate-buffer))
 
-(defvar bibtex-entry-field-alist
-  '(
-    ("Article" . ((("author" "title" "journal" "year")
-		   ("volume" "number" "pages" "month" "note"))
-		  (("author" "title")
-		   ("journal" "year" "volume" "number" "pages"
-		    "month" "note"))))
-    ("Book" . ((("author" "title" "publisher" "year")
-		("editor" "volume" "number" "series" "address"
-		 "edition" "month" "note"))))
-    ("Booklet" . ((("title")
-		   ("author" "howpublished" "address" "month" "year" "note"))))
-    
-    ;; France: Dipl\^{o}me d'Etudes Approfondies (similar to Master's)
-;    ("DEAthesis" . ((("author" "title" "school" "year")
-;		     ("address" "month" "note"))))
-    
-    ("InBook" . ((("author" "title" "chapter" "publisher" "year")
-		  ("editor" "pages" "volume" "number" "series" "address"
-		   "edition" "month" "type" "note"))
-		 (("author" "title" "chapter")
-		  ("publisher" "year" "editor" "pages" "volume" "number"
-		   "series" "address" "edition" "month" "type" "note"))))
-
-
-    ("InCollection" . ((("author" "title"
-			 "booktitle" "publisher" "year")
-			("editor" "volume" "number" "series" "type" "chapter"
-			 "pages" "address" "edition" "month" "note"))
-		       (("author" "title")
-			("booktitle" "publisher" "year"
-			 "editor" "volume" "number" "series" "type" "chapter"
-			 "pages" "address" "edition" "month" "note"))))
+(define-key bibtex-mode-map [menu-bar entry-types]
+  (cons "Entry-Types" (make-sparse-keymap "Entry-Types")))
+(define-key bibtex-mode-map [menu-bar entry-types bibtex-preamble]
+  '("Preamble" . bibtex-preamble))
+(define-key bibtex-mode-map [menu-bar entry-types bibtex-string]
+  '("String" . bibtex-string))
+(define-key bibtex-mode-map [menu-bar entry-types bibtex-Misc]
+  '("Miscellaneous" . bibtex-Misc))
+(define-key bibtex-mode-map [menu-bar entry-types bibtex-Unpublished]
+  '("Unpublished" . bibtex-Unpublished))
+(define-key bibtex-mode-map [menu-bar entry-types bibtex-Manual]
+  '("Technical Manual" . bibtex-Manual))
+(define-key bibtex-mode-map [menu-bar entry-types bibtex-TechReport]
+  '("Technical Report" . bibtex-TechReport))
+(define-key bibtex-mode-map [menu-bar entry-types bibtex-MastersThesis]
+  '("Master's Thesis" . bibtex-MastersThesis))
+(define-key bibtex-mode-map [menu-bar entry-types bibtex-PhdThesis]
+  '("PhD. Thesis" . bibtex-PhdThesis))
+(define-key bibtex-mode-map [menu-bar entry-types bibtex-Booklet]
+  '("Booklet (Bound, but no Publisher/Institution)" . bibtex-Booklet))
+(define-key bibtex-mode-map [menu-bar entry-types bibtex-Book]
+  '("Book" . bibtex-Book))
+(define-key bibtex-mode-map [menu-bar entry-types bibtex-Proceedings]
+  '("Conference Proceedings" . bibtex-Proceedings))
+(define-key bibtex-mode-map [menu-bar entry-types bibtex-InBook]
+  '("Chapter or Pages in a Book" . bibtex-InBook))
+(define-key bibtex-mode-map [menu-bar entry-types bibtex-InCollection]
+  '("Article in a Collection" . bibtex-InCollection))
+(define-key bibtex-mode-map [menu-bar entry-types bibtex-InProceedings]
+  '("Article in Conference Proceedings" . bibtex-InProceedings))
+(define-key bibtex-mode-map [menu-bar entry-types bibtex-Article]
+  '("Article in Journal" . bibtex-Article))
 
 
-    ("InProceedings" . ((("author" "title" "booktitle" "year")
-			 ("editor" "volume" "number" "series" "pages"
-			  "organization" "publisher" "address" "month" "note"))
-			(("author" "title")
-			 ("editor" "volume" "number" "series" "pages"
-			  "booktitle" "year"
-			  "organization" "publisher" "address" "month" "note"))))
-
-
-    ("Manual" . ((("title")
-		  ("author" "organization" "address" "edition" "year"
-		   "month" "note"))))
+
+;;; INTERNAL VARIABLES
 
-    ("MastersThesis" . ((("author" "title" "school" "year")
-			 ("address" "month" "note" "type"))))
-
-    ("Misc" . ((()
-		("author" "title" "howpublished" "year" "month" "note"))))
+(defvar bibtex-pop-previous-search-point nil)
+;; Next point where bibtex-pop-previous starts looking for a similar
+;; entry.
 
-    ("PhdThesis" . ((("author" "title" "school" "year")
-		     ("address" "month" "type" "note"))))
-
-    ("Proceedings" . ((("title" "year")
-		       ("editor" "volume" "number" "series" "publisher"
-			"organization" "address" "month" "note"))))
+(defvar bibtex-pop-next-search-point nil)
+;; Next point where bibtex-pop-next starts looking for a similar entry.
 
-    ("TechReport" . ((("author" "title" "institution" "year")
-		      ("type" "number" "address" "month" "note"))))
-
-    ("Unpublished" . ((("author" "title" "note")
-		       ("year" "month"))))
-    )
+(defvar bibtex-completion-candidates nil)
+;; Candidates for bibtex-complete-string. Initialized from
+;; bibtex-predefined-strings and bibtex-string-files. This variable is
+;; buffer-local.
+(make-variable-buffer-local 'bibtex-completion-candidates)
 
-  "List of (entry-name (required optional) (crossref-required crossref-optional))
-tripples.  If the third element is nil, then the first pair can be used.  Required
-and optional are lists of strings.  All entry creation functions use this variable
-to generate entries, and bibtex-entry ensures the entry type is valid.  This 
-variable can be used for example to make bibtex manipulate a different set of entry
-types, e.g. a crossreference document of organization types.")
-
+
+;;; FUNCTIONS to parse the BibTeX entries
 
-;;; A bibtex file is a sequence of entries, either string definitions
-;;; or reference entries.  A reference entry has a type part, a
-;;; key part, and a comma-separated sequence of fields.  A string
-;;; entry has a single field.  A field has a left and right part,
-;;; separated by a '='.  The left part is the name, the right part is
-;;; the text.  Here come the definitions allowing to create and/or parse
-;;; entries and fields:
-
-;;; fields
 (defun bibtex-cfield (name text)
-  "Create a regexp for a bibtex field of name NAME and text TEXT"
+  ;; Create a regexp for a BibTeX field of name NAME and text TEXT.
   (concat ",[ \t\n]*\\("
 	  name
 	  "\\)[ \t\n]*=[ \t\n]*\\("
 	  text
 	  "\\)"))
-(defconst bibtex-name-in-cfield 1
-  "The regexp subexpression number of the name part in bibtex-cfield.")
-(defconst bibtex-text-in-cfield 2
-  "The regexp subexpression number of the text part in bibtex-cfield.")
+(defconst bibtex-name-in-cfield 1)
+;; The regexp subexpression number of the name part in bibtex-cfield.
 
-;;; KAWATA Yasuro <yasuro@qqqq.maekawa.is.uec.ac.jp> reported bug that "/"
-;;; was not premitted in field names.  The old value of this var was:
-;;;    "[A-Za-z][---A-Za-z0-9:_+]*"
-;;; According to the LaTeX manual, page 71, the legal values are letters,
-;;; digits, and punctuation other than comma.  Section 2.1 defines
-;;; punctuation as:
-;;;     .:;,?!`'()[]-/*@
-;;; and says that += can be used in normal text.  Specifically #$%&~_^\{}
-;;; are called out as special chars.  Some experimentation with LaTeX
-;;; indicates that # and ~ definitely don't work, but that the following
-;;; citation does! \cite{a0.:;?!`'()[]-/*@_&$^+=|<>}.  I chose here to
-;;; permit _ since it was previously allowed, but otherwise to only handle
-;;; punc and +=
-;;; Amendment:  I couldn't get a regexp with both "[]"'s and hyphen to
-;;; work.  It looks like you need them both to be the first entries in a
-;;; regexp pattern. [alarson:19930315.0900CST]
-;;;
-;;; New amendment[MB]: I have corrected the following regexp according to 
-;;; emacs19 rules.  I also added ']' to the list of characters allowed in 
-;;; a field name.
+(defconst bibtex-text-in-cfield 2)
+;; The regexp subexpression number of the text part in bibtex-cfield.
 
-(defconst bibtex-field-name "[A-Za-z][]A-Za-z0-9.:;?!`'()/*@_+=-]*"
-  "Regexp defining the name part of a bibtex field.")
+(defconst bibtex-field-name "[A-Za-z][]A-Za-z0-9.:;?!`'()/*@_+=-]*")
+;; Regexp defining the name part of a BibTeX field.
 
-;; bibtex-field-text must be able to handle
-;;   title = "Proc. Fifteenth Annual" # STOC,
-;;   month = "10~" # jan,
-;;   year = "{\noopsort{1973c}}1981",
-;;   month = apr # "-" # may,
-;;   key = {Volume-2},
-;;   note = "Volume~2 is listed under Knuth \cite{book-full}"
-;; i have added a few of these, but not all! -- MON
-
-(defconst bibtex-field-const
-  "[0-9A-Za-z][A-Za-z0-9:_+-]*"
+(defconst bibtex-field-const "[0-9A-Za-z][A-Za-z0-9:_+-]*"
   "Format of a bibtex field constant.")
 
 (defconst bibtex-field-string
   (concat
-    "\"[^\"]*[^\\\\]\"\\|\"\"")
-  "Match either a string or an empty string.")
+   "\\("
+   "{\\(\\({\\(\\({[^}]*}\\)\\|\\([^{}]\\)\\)*}\\)\\|\\([^{}]\\)\\)*}"
+   ;; maximal twice nested {}
+   "\\)\\|\\("
+   "\"[^\"]*[^\\\\]\"\\|\"\"\\)"))
+;; Match either a string or an empty string.
 
 (defconst bibtex-field-string-or-const
-  (concat bibtex-field-const "\\|" bibtex-field-string)
-  "Match either bibtex-field-string or bibtex-field-const.")
+  (concat bibtex-field-const "\\|" bibtex-field-string))
+;; Match either bibtex-field-string or bibtex-field-const.
 
 (defconst bibtex-field-text
   (concat
     "\\(" bibtex-field-string-or-const "\\)"
         "\\([ \t\n]+#[ \t\n]+\\(" bibtex-field-string-or-const "\\)\\)*\\|"
-    "{[^{}]*[^\\\\]}")
-  "Regexp defining the text part of a bibtex field: either a string, or
-an empty string, or a constant followed by one or more # / constant pairs.
-Also matches simple {...} patterns.")
-
-;(defconst bibtex-field-text
-;  "\"[^\"]*[^\\\\]\"\\|\"\"\\|[0-9A-Za-z][A-Za-z0-9:_+-]*"
-;  "Regexp defining the text part of a bibtex field: either a string, or an empty string, or a constant.")
+    "{[^{}]*[^\\\\]}"))
+;; Regexp defining the text part of a BibTeX field: either a string,
+;; or an empty string, or a constant followed by one or more # /
+;; constant pairs. Also matches simple {...} patterns.
 
 (defconst bibtex-field
-  (bibtex-cfield bibtex-field-name bibtex-field-text)
-  "Regexp defining the format of a bibtex field")
+  (bibtex-cfield bibtex-field-name bibtex-field-text))
+;; Regexp defining the format of a BibTeX field.
+
+(defconst bibtex-name-in-field bibtex-name-in-cfield)
+;; The regexp subexpression number of the name part in BibTeX-field.
 
-(defconst bibtex-name-in-field bibtex-name-in-cfield
-  "The regexp subexpression number of the name part in bibtex-field")
-(defconst bibtex-text-in-field bibtex-text-in-cfield
-  "The regexp subexpression number of the text part in bibtex-field")
+(defconst bibtex-text-in-field bibtex-text-in-cfield)
+;; The regexp subexpression number of the text part in BibTeX-field.
 
-;;; references
 (defconst bibtex-reference-type
-  "@[A-Za-z]+"
-  "Regexp defining the type part of a bibtex reference entry")
+  "@[A-Za-z]+")
+;; Regexp defining the type part of a BibTeX reference entry.
+
 (defconst bibtex-reference-head
-  (concat "^[ \t]*\\("
+  (concat "^\\( \\|\t\\)*\\("
 	  bibtex-reference-type
 	  "\\)[ \t]*[({]\\("
 	  bibtex-field-name
-	  "\\)")
-  "Regexp defining format of the header line of a bibtex reference entry")
-(defconst bibtex-type-in-head 1
-  "The regexp subexpression number of the type part in bibtex-reference-head")
-(defconst bibtex-key-in-head 2
-  "The regexp subexpression number of the key part in
-bibtex-reference-head")
+	  "\\)"))
+;; Regexp defining format of the header line of a BibTeX reference
+;; entry.
+
+(defconst bibtex-type-in-head 2)
+;; The regexp subexpression number of the type part in
+;; bibtex-reference-head.
+
+(defconst bibtex-key-in-head 3)
+;; The regexp subexpression number of the key part in
+;; bibtex-reference-head.
 
 (defconst bibtex-reference
-  (concat
-   ;; This is the unparenthesized equivalent of bibtex-reference-head:
-   "^[ \t]*"
-   bibtex-reference-type
-   "[ \t]*[({]\\("
-   bibtex-field-name
-   "\\)"
-   ;; End of unparenthesized equivalent of bibtex-reference-head
-   "\\([ \t\n]*" bibtex-field "\\)*"
-   "[ \t\n]*[})]")
-  "Regexp defining the format of a bibtex reference entry")
-(defconst bibtex-type-in-reference bibtex-type-in-head
-  "The regexp subexpression number of the type part in bibtex-reference")
-(defconst bibtex-key-in-reference bibtex-key-in-head
-  "The regexp subexpression number of the key part in
-bibtex-reference")
+  (concat bibtex-reference-head
+	  "\\([ \t\n]*" bibtex-field "\\)*"
+	  "[ \t\n]*[})]"))
+;; Regexp defining the format of a BibTeX reference entry.
 
-;;; strings
+(defconst bibtex-type-in-reference bibtex-type-in-head)
+;; The regexp subexpression number of the type part in
+;; bibtex-reference.
+
+(defconst bibtex-key-in-reference bibtex-key-in-head)
+;; The regexp subexpression number of the key part in
+;; bibtex-reference.
+
 (defconst bibtex-string
   (concat "^[ \t]*@[sS][tT][rR][iI][nN][gG][ \t\n]*[({][ \t\n]*\\("
 	  bibtex-field-name
 	  "\\)[ \t\n]*=[ \t\n]*\\("
 	  bibtex-field-text
-	  "\\)[ \t\n]*[})]")
-  "Regexp defining the format of a bibtex string entry")
-(defconst bibtex-name-in-string 1
-  "The regexp subexpression of the name part in bibtex-string")
-(defconst bibtex-text-in-string 2
-  "The regexp subexpression of the text part in bibtex-string")
-
-(defconst bibtex-name-alignment 2
-  "Alignment for the name part in BibTeX fields.
-Chosen on aesthetic grounds only.")
-
-(defconst bibtex-text-alignment (length "  organization = ")
-  "Alignment for the text part in BibTeX fields.
-Equal to the space needed for the longest name part.")
+	  "\\)[ \t\n]*[})]"))
+;; Regexp defining the format of a BibTeX string entry.
 
-(defun bibtex-current-entry-label (&optional include-cite kill)
-  "Return the label of the bibtex entry containing, or preceding point.
-Optional argument INCLUDE-CITE, if true means put a '\\cite{}' around the
-returned value.  Second optional argument KILL, if true, means place the
-returned value in the kill buffer.  Interactively; providing prefix
-argument makes INCLUDE-CITE true, and kill is true by default.
+(defconst bibtex-name-in-string 1)
+;; The regexp subexpression of the name part in bibtex-string.
 
-Rationale:
-The intention is that someone will write a function that can be bound to
-a mouse key so that people entering TeX can just mouse on the bibtex entry
-and have the citation key inserted at the current point (which will almost
-certainly be in some other buffer).  In the interim this function is 
-marginally useful for keyboard binding and is not bound by default.  
-Suggested binding is ^C-k."
-  (interactive (list current-prefix-arg t))
-  (save-excursion
-    (beginning-of-bibtex-entry)
-    (re-search-forward bibtex-reference-head (save-excursion (end-of-bibtex-entry) (point)))
-    (let* ((key (buffer-substring (match-beginning bibtex-key-in-head)
-				  (match-end bibtex-key-in-head)))
-	   (val (if include-cite
-		    (format "\\cite{%s}" key)
-		    key)))
-      (if kill
-	  (kill-new val))
-      val)))
+(defconst bibtex-text-in-string 2)
+;; The regexp subexpression of the text part in bibtex-string.
 
-;;; bibtex mode:
-
-;;;###autoload
-(defun bibtex-mode () 
-  "Major mode for editing bibtex files.
-
-\\{bibtex-mode-map}
-
-A command such as \\[bibtex-Book] will outline the fields for a BibTeX book entry.
-
-The optional fields start with the string OPT, and thus ignored by BibTeX.
-The OPT string may be removed from a field with \\[bibtex-remove-OPT].
-\\[bibtex-kill-optional-field] kills the current optional field entirely.
-\\[bibtex-remove-double-quotes] removes the double-quotes around the text of
-the current field.  \\[bibtex-empty-field] replaces the text of the current
-field with the default \"\".
+(defconst bibtex-name-alignment 2)
+;; Alignment for the name part in BibTeX fields. Chosen on aesthetic
+;; grounds only.
 
-The command \\[bibtex-clean-entry] cleans the current entry, i.e. (i) removes
-double-quotes from entirely numerical fields, (ii) removes OPT from all
-non-empty optional fields, (iii) removes all empty optional fields, and (iv)
-checks that no non-optional fields are empty.
-
-Use \\[bibtex-find-text] to position the dot 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:
+(defconst bibtex-text-alignment (length "  organization = "))
+;; Alignment for the text part in BibTeX fields. Equal to the space
+;; needed for the longest name part.
 
-  Functions:
-    find-bibtex-duplicates
-    find-bibtex-entry-location
-    hide-bibtex-entry-bodies
-    sort-bibtex-entries
-    validate-bibtex-buffer
 
-  Variables:
-    bibtex-clean-entry-zap-empty-opts
-    bibtex-entry-field-alist
-    bibtex-include-OPTannote
-    bibtex-include-OPTcrossref
-    bibtex-include-OPTkey
-    bibtex-maintain-sorted-entries
-    bibtex-mode-user-optional-fields
+
+;;; HELPER FUNCTIONS
 
-Fields:
-    address
-           Publisher's address
-    annote
-           Long annotation used for annotated bibliographies (begins sentence)
-    author
-           Name(s) of author(s), in BibTeX name format
-    booktitle
-           Book title when the thing being referenced isn't the whole book.
-           For book entries, the title field should be used instead.
-    chapter
-           Chapter number
-    crossref
-	   The database key of the entry being cross referenced.
-    edition
-           Edition of a book (e.g., \"second\")
-    editor
-           Name(s) of editor(s), in BibTeX name format.
-           If there is also an author field, then the editor field should be
-           for the book or collection that the work appears in
-    howpublished
-            How something strange has been published (begins sentence)
-    institution
-           Sponsoring institution
-    journal
-           Journal name (macros are provided for many)
-    key
-           Alphabetizing and labeling key (needed when no author or editor)
-    month
-           Month (macros are provided)
-    note
-           To help the reader find a reference (begins sentence)
-    number
-           Number of a journal or technical report
-    organization
-           Organization (sponsoring a conference)
-    pages
-           Page number or numbers (use `--' to separate a range)
-    publisher
-           Publisher name
-    school
-           School name (for theses)
-    series
-           The name of a series or set of books.
-           An individual book will will also have it's own title
-    title
-           The title of the thing being referenced
-    type
-           Type of a technical report (e.g., \"Research Note\") to be used
-           instead of the default \"Technical Report\"
-    volume
-           Volume of a journal or multivolume work
-    year
-           Year---should contain only numerals
----------------------------------------------------------
-Entry to this mode calls the value of bibtex-mode-hook if that value is
-non-nil."
-  (interactive)
-  (kill-all-local-variables)
-  (set-syntax-table bibtex-mode-syntax-table)
-  (use-local-map bibtex-mode-map)
-  (setq major-mode 'bibtex-mode)
-  (setq mode-name "BibTeX")
-  (set-syntax-table bibtex-mode-syntax-table)
-  (setq local-abbrev-table bibtex-mode-abbrev-table)
-  (make-local-variable 'paragraph-start)
-  (make-local-variable 'comment-start)
-  (setq comment-start "%")
-  (setq paragraph-start "^[ \f\n\t]*$")
-  (auto-fill-mode 1)			; nice alignments
-  (setq left-margin (+ bibtex-text-alignment 1))
+(defun assoc-ignore-case (string alist)
+  ;; Return non-nil if STRING is `equal' to the car of an element of
+  ;; LIST. Comparison is done with case ignored. The value is actually
+  ;; the element of LIST whose car is `equal' to STRING.
+  (or (assoc string alist)
+      (while (and alist
+		  (not (string-equal
+                        (downcase string)
+                        (downcase (car (car alist))))))
+	(setq alist (cdr alist)))
+      (car alist)))
 
-  (run-hooks 'bibtex-mode-hook))
+(defun member-of-regexp (string list)
+  ;; Return non-nil if STRING is exactly matched by an element of
+  ;; LIST. This function is influenced by the actual value of
+  ;; `case-fold-search'. The value is actually the tail of LIST whose
+  ;; car matches STRING.
+  (while
+      (and
+       list
+       (not
+        (string-match
+         (concat "^" (car list) "$")
+         string)))
+    (setq list (cdr list)))
+  list)
 
-(defun bibtex-move-outside-of-entry ()
-  "Make sure we are outside of a bib entry"
-  (cond ((or
-	  (= (point) (point-max))
-	  (= (point) (point-min))
-	  (looking-at "[ \n]*@")
-	  )
-	 t)
-	(t
-	 (backward-paragraph)
-	 (forward-paragraph)))
-  (re-search-forward "[ \t\n]*" (point-max) t))
-
-(defun ispell-abstract ()
-  (interactive)
-  (beginning-of-bibtex-entry)
-  (re-search-forward "^[ \t]*[OPT]*abstract[ \t]*=")
-  (ispell-region (point)
-		 (save-excursion (forward-sexp) (point))))
-
-(defun beginning-of-bibtex-entry ()
-  (interactive)
-  (re-search-backward "^@" nil 'move))
+(defun assoc-of-regexp (string alist)
+  ;; Return non-nil if STRING is exactly matched by the car of an
+  ;; element of LIST. This function is influenced by the actual value
+  ;; of `case-fold-search'. The value is actually the element of LIST
+  ;; whose car matches STRING.
+  (while
+      (and
+       alist
+       (not
+        (string-match
+         (concat "^" (car (car alist)) "$")
+         string)))
+    (setq alist (cdr alist)))
+  (car alist))
 
 (defun skip-whitespace-and-comments ()
-  ;; It might be a good idea to have forward-sexp with argument 0 do what
-  ;; this function tries to do, namely skip whitespace and comments.
-  ;; Maybe a better name for this would be skip-to-next-sexp.
-  ;; alternative implementation:
-  ;;   (let ((parse-sexp-ignore-comments t))
-  ;;     (forward-sexp 1)
-  ;;     (forward-sexp -1))
-  ;; but I've had problems with this not getting the parse of comments
-  ;; right going backward if they contain unbalanced expressions or string
-  ;; quotes. [alarson:19920217.1021CST]
   (let ((md (match-data)))
     (unwind-protect
 	(while (cond ((looking-at "\\s>+\\|\\s +")
@@ -742,39 +705,54 @@
 		      (re-search-forward "\\s>"))))		      
       (store-match-data md))))
 
-;;; [alarson:19920214.1007CST]
-(defun end-of-bibtex-entry ()
-  "If inside an entry, move to the end of it, otherwise move to the end
-of the next entry."
-  (interactive)
-  ;; if point was previously at the end of an entry, this puts us
-  ;; inside the next entry, otherwise we remain in the current one.
-  (progn
-    (skip-whitespace-and-comments)
-;;;     (skip-chars-forward " \t\n") 
-    (end-of-line))
-  (beginning-of-bibtex-entry)
-  (let ((parse-sexp-ignore-comments t))
-    (forward-sexp) ; skip entry type
-    (forward-sexp) ; skip entry body
-    ))
-;(defun end-of-bibtex-entry ()
-;  (interactive)
-;  (re-search-forward "}$" nil 'move))
-  
-(defun ispell-bibtex-entry ()
-  (interactive)
-  (ispell-region (progn (beginning-of-bibtex-entry) (point))
-		 (progn (end-of-bibtex-entry) (point))))
+(defun map-bibtex-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 true, FUN will not be called
+  ;; for @string entries.
+  (bibtex-beginning-of-entry)
+  (while (re-search-forward "^@[^{]*{[ \t]*\\([^, ]*\\)" nil t)
+    (if (and bibtex-sort-ignore-string-entries
+	     (string-equal "@string{"
+                           (downcase (buffer-substring
+                                      (match-beginning 0)
+                                      (match-beginning 1)))))
+	nil
+      (funcall fun (buffer-substring (match-beginning 1) (match-end 1))))))
 
-(defun narrow-to-bibtex-entry ()
-  (interactive)
-  (save-excursion
-    (narrow-to-region (progn (beginning-of-bibtex-entry) (point))
-		      (progn (end-of-bibtex-entry) (point)))))
+(defun bibtex-flash-head ()
+  ;; Flash at BibTeX reference head before point, if exists.
+  (let ((flash))
+    (cond ((re-search-backward bibtex-reference-head (point-min) t)
+	   (goto-char (match-beginning bibtex-type-in-head))
+	   (setq flash (match-end bibtex-key-in-reference)))
+	  (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-move-outside-of-entry ()
+  ;; Make sure we are outside of a BibTeX entry.
+  (cond ((or
+	  (= (point) (point-max))
+	  (= (point) (point-min))
+	  (looking-at "[ \n]*@")
+	  )
+	 t)
+	(t
+	 (backward-paragraph)
+	 (forward-paragraph)))
+  (re-search-forward "[ \t\n]*" (point-max) t))
 
 (defun beginning-of-first-bibtex-entry ()
+  ;; Go to the beginning of the first BibTeX entry in buffer.
   (goto-char (point-min))
   (cond
    ((re-search-forward "^@" nil 'move)
@@ -782,10 +760,682 @@
    ((and (bobp) (eobp))
     nil)
    (t
-    (message "Warning: No bibtex entries found!"))))
+    (message "Warning: No BibTeX entries found!"))))
+
+(defun bibtex-inside-field ()
+  ;; Try to avoid point being at end of a BibTeX field.
+  (end-of-line)
+  (skip-chars-backward " \t")		;MON - maybe delete these chars?
+  (cond ((= (preceding-char) ?,)
+	 (forward-char -2))) ; -1 --> -2 sct@dcs.edinburgh.ac.uk
+  (cond ((= (preceding-char) (aref bibtex-field-right-delimiter 0))
+	 (forward-char -1))))		;MON - only go back if quote
+
+(defun bibtex-enclosing-field ()
+  ;; Search for BibTeX field enclosing point. Point moves to end of
+  ;; field; also, use match-beginning and match-end to parse the field.
+  ;; sct@dcs.edinburgh.ac.uk
+  (let ((old-point (point)))
+    (condition-case errname
+ 	(bibtex-enclosing-regexp bibtex-field)
+      (search-failed
+       (goto-char old-point)
+       (error "Can't find enclosing BibTeX field.")))))
+
+(defun bibtex-enclosing-reference ()
+  ;; Search for BibTeX reference enclosing point. Point moves to begin
+  ;; of reference. (match-end 0) denotes end of reference.
+  ;; Hacked up for speed. Parsing isn't guaranteed any more.
+  ;; schoef@informatik.uni-oldenburg.de
+  ;; sct@dcs.edinburgh.ac.uk
+  (let ((old-point (point)))
+    (if (not
+         (re-search-backward
+          "^@[A-Za-z]+[ \t\n]*[{(][^, \t\n]*[ \t\n]*,"
+          (point-min) t))
+        (progn
+          (error "Can't find enclosing BibTeX reference.")
+          (goto-char old-point)))
+    (let ((pnt (point)))
+      (if (not
+           (re-search-forward "^[)}]$" (point-max) t))
+          (progn
+            (error "Can't find enclosing BibTeX reference.")
+            (goto-char old-point))
+        (goto-char pnt)))))
+
+(defun bibtex-enclosing-regexp (regexp)
+  ;; Search for REGEXP enclosing point. Point moves to end of
+  ;; REGEXP. See also match-beginning and match-end. If an enclosing
+  ;; REGEXP is not found, signals search-failed; point is left in an
+  ;; undefined location.
+  ;; Doesn't something like this exist already?
+  ; compute reasonable limits for the loop
+  (let* ((initial (point))
+	 (right (if (re-search-forward regexp (point-max) t)
+		    (match-end 0)
+		  (point-max)))
+	 (left
+	  (progn
+	    (goto-char initial)
+	    (if (re-search-backward regexp (point-min) t)
+		(match-beginning 0)
+	      (point-min)))))
+    ; within the prescribed limits, loop until a match is found
+    (goto-char left)
+    (re-search-forward regexp right nil 1)
+    (if (> (match-beginning 0) initial)
+	(signal 'search-failed (list regexp)))	  
+    (while (<= (match-end 0) initial)
+      (re-search-forward regexp right nil 1)
+      (if (> (match-beginning 0) initial)
+	  (signal 'search-failed (list regexp))))
+    ))
+
+(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 ((return-string string)
+        case-fold-search
+        (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.
+  (let* ((string-length (length string))
+         (len (if (numberp len)
+                  (min len string-length)
+                len))
+         (return-string (if (numberp len)
+                            (substring string 0 len)))
+         (index len)
+         (vowels '(?a ?e ?i ?o ?u ?A ?E ?I ?O ?U)))
+    (if (numberp len)
+        (progn
+          (while (and
+                  (< index string-length) 
+                  (member (elt return-string
+                               (1- (length return-string)))
+                          vowels))
+            (setq return-string (concat return-string
+                                        (substring
+                                         string index (1+ index)))
+                  index (1+ index)))
+          return-string)
+      string)))        
+
+(defun bibtex-generate-autokey ()
+  "Generates automatically a key from the author/editor and the title field.
+The generation algorithm works as follows:
+  1. If there is a non-empty author (preferred) or editor field,
+     use it for the name part of the key.
+  2. Change any substring found in `bibtex-autokey-name-change-strings' 
+     to the corresponding new one (see documentation of this variable
+     for further detail).
+  3. For every of the first `bibtex-autokey-names' names in the
+     \"name\" field, determine the last name.
+  4. From every last name, take at least `bibtex-autokey-name-length'
+     characters (abort only after a consonant or at a word end).
+  5. Build the name part of the key by concatenating all abbreviated last
+     names with the string `bibtex-autokey-name-separator' between
+     any two.
+  6. 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).
+  7. For the title part of the key change the contents of the \"title\"
+     field of the reference according to
+     `bibtex-autokey-titleword-change-strings' to the corresponding
+     new one (see documentation of this variable for further detail).
+  8. Abbreviate the result to the string up to (but not including) the
+     first occurence of a regexp matched by the items of
+     `bibtex-autokey-title-terminators' and delete the first
+     word if it appears in `bibtex-autokey-titleword-first-ignore'. 
+     Build the title part of the key by using at least the first
+     `bibtex-autokey-titlewords' capitalized words from this
+     abbreviated title. If the abbreviated title ends after maximal
+     `bibtex-autokey-titlewords' + `bibtex-autokey-titlewords-stretch'
+     capitalized words, all capitalized words from the abbreviated title
+     are used. 
+  9. For every used title word that appears in
+     `bibtex-autokey-titleword-abbrevs' use the corresponding abbreviation
+     (see documentation of this variable for further detail).
+ 10. 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).
+ 11. Build the title part of the key by concatenating all abbreviated
+     title words with the string `bibtex-autokey-titleword-separator'
+     between any two.
+ 12. At least, to get the key, concatenate the name part, the year part
+     and the title part with `bibtex-autokey-name-year-separator'
+     between the name and the year if both are non-empty and
+     `bibtex-autokey-year-title-separator' between the year and
+     the title if both are non-empty."
 
-(defun hide-bibtex-entry-bodies (&optional arg)
-  "Hide all lines between first and last bibtex entries not beginning with @.
+  (let* ((pnt (point))
+         (min
+          (progn
+            (bibtex-beginning-of-entry)
+            (point)))
+         (max
+          (progn
+            (bibtex-end-of-entry)
+            (point)))
+         (namefield
+          (progn
+            (goto-char min)
+            (if (or
+                 (search-forward-regexp "^[ \t]*author[ \t]*=" max t)
+                 (search-forward-regexp "^[ \t]*editor[ \t]*=" max t))
+                (let* (bibtex-help-message
+                       (start (progn
+                                (bibtex-find-text t)
+                                (point)))
+                       (end (progn
+                              (bibtex-find-text nil)
+                              (point))))
+                  (bibtex-autokey-change
+                   (buffer-substring start end)
+                   bibtex-autokey-name-change-strings))
+              "")))
+         (namelist
+          (mapcar
+           (function
+            (lambda (fullname)
+              (bibtex-autokey-abbrev
+               (if (string-match "," fullname)
+                   (substring fullname 0 (match-beginning 0))
+                 (progn
+                   (if (string-match " [^ ]*$" fullname)
+                       (substring
+                        fullname (1+ (match-beginning 0)))
+                     fullname)))
+               bibtex-autokey-name-length)))
+           ;; Gather all names into a list
+           (let (names
+                 (counter 0))
+             (while (and
+                     (not (equal namefield ""))
+                     (or
+                      (not (numberp bibtex-autokey-names))
+                      (< counter bibtex-autokey-names)))
+               (if (string-match " and " namefield)
+                   (progn
+                     (setq
+                      names
+                      (append names
+                              (list
+                               (downcase
+                                (substring
+                                 namefield 0 (match-beginning 0)))))
+                      namefield
+                      (substring namefield (match-end 0))))
+                 (setq names
+                       (append names (list (downcase namefield)))
+                       namefield ""))
+               (setq counter (1+ counter)))
+             names)))
+         (namepart (mapconcat (function (lambda (name) name))
+                              namelist
+                              bibtex-autokey-name-separator))
+         (yearfield
+          (progn
+            (goto-char min)
+            (if (search-forward-regexp
+                 "^[ \t]*year[ \t]*=[ \t]*\\([0-9]*\\)" max t)
+                (buffer-substring (match-beginning 1) (match-end 1))
+              "")))
+         (yearpart
+          (if (equal yearfield "")
+              ""
+            (substring yearfield
+                       (- (length yearfield)
+                          bibtex-autokey-year-length))))
+         (titlestring
+          (let ((case-fold-search t)
+                (titlefield
+                 (progn
+                   (goto-char min)
+                   (if (search-forward-regexp
+                        "^[ \t]*title[ \t]*=" max t)
+                       (let* (bibtex-help-message
+                              (start (progn
+                                       (bibtex-find-text t)
+                                       (point)))
+                              (end (progn
+                                     (bibtex-find-text nil)
+                                     (point))))
+                         (bibtex-autokey-change
+                          (buffer-substring start end)
+                          bibtex-autokey-titleword-change-strings))
+                     "")))
+                case-fold-search
+                (index 0)
+                (numberofitems
+                 (length bibtex-autokey-title-terminators)))
+            (while (< index numberofitems)
+              (if (string-match
+                   (elt bibtex-autokey-title-terminators index)
+                   titlefield)
+                  (setq titlefield
+                        (substring titlefield 0 (match-beginning 0))))
+              (setq index (1+ index)))
+            titlefield))
+         (titlelist
+          (mapcar
+           (function
+            (lambda (titleword)
+              (let ((abbrev
+                     (assoc-of-regexp
+                      titleword bibtex-autokey-titleword-abbrevs)))
+                (if abbrev
+                    (elt abbrev 1)
+                  (bibtex-autokey-abbrev
+                   titleword
+                   bibtex-autokey-titleword-length)))))
+           ;; Gather all titlewords into a list
+           (let (titlewords
+                 titlewords-extra
+                 case-fold-search
+                 (counter 0)
+                 (first t))
+             (while (and
+                     (not (equal titlestring ""))
+                     (or
+                      (not (numberp bibtex-autokey-titlewords))
+                      (< counter (+
+                                  bibtex-autokey-titlewords
+                                  bibtex-autokey-titlewords-stretch))))
+               (if (string-match "\\b[A-Z][A-Za-z0-9]*" titlestring)
+                   (let* ((end-match (match-end 0))
+                          (titleword
+                           (downcase (substring titlestring
+                                                (match-beginning 0)
+                                                end-match))))
+                     (if (or
+                          (not (numberp bibtex-autokey-titlewords))
+                          (< counter bibtex-autokey-titlewords))
+                         (if (and
+                              first
+                              (member-of-regexp
+                               titleword
+                               bibtex-autokey-titleword-first-ignore))
+                             (setq counter -1)
+                           (setq titlewords
+                                 (append titlewords (list titleword))))
+                       (setq
+                        titlewords-extra
+                        (append titlewords-extra (list titleword))))
+                     (setq titlestring
+                           (substring titlestring end-match)))
+                 (setq titlestring ""))
+               (setq first nil
+                     counter (1+ counter)))
+             (if (string-match "\\b[A-Z][^ ]*\\b" titlestring)
+                 titlewords
+               (append titlewords titlewords-extra)))))
+         (titlepart (mapconcat (function (lambda (name) name))
+                               titlelist
+                               bibtex-autokey-titleword-separator))
+         (autokey
+          (concat
+           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)))
+    (goto-char pnt)
+    autokey))
+
+
+
+;;; INTERACTIVE FUNCTIONS:
+
+;;;###autoload
+(defun bibtex-mode () 
+  "Major mode for editing BibTeX files.
+
+\\{bibtex-mode-map}
+
+A command such as \\[bibtex-Book] will outline the fields for a BibTeX book entry.
+
+The optional fields start with the string OPT, and thus ignored by BibTeX.
+The OPT string may be removed from a field with \\[bibtex-remove-OPT].
+\\[bibtex-kill-optional-field] kills the current optional field entirely.
+\\[bibtex-remove-double-quotes-or-braces] 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. (i) removes
+double-quotes or braces from entirely numerical fields, (ii) removes
+OPT from all non-empty optional fields, (iii) removes all empty
+optional fields, and (iv) checks that no non-optional fields are empty.
+
+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-print-help-message
+    bibtex-beginning-of-entry
+    bibtex-end-of-entry
+    bibtex-ispell-abstract
+    bibtex-narrow-to-entry
+    bibtex-hide-entry-bodies
+    bibtex-sort-entries
+    bibtex-validate-buffer
+    bibtex-pop-previous
+    bibtex-pop-next
+    bibtex-complete-string
+
+  Variables:
+    bibtex-field-left-delimiter
+    bibtex-field-right-delimiter
+    bibtex-include-OPTcrossref
+    bibtex-include-OPTkey
+    bibtex-include-OPTannote
+    bibtex-mode-user-optional-fields
+    bibtex-clean-entry-zap-empty-opts
+    bibtex-sort-ignore-string-entries
+    bibtex-maintain-sorted-entries
+    bibtex-entry-field-alist
+    bibtex-predefined-strings
+    bibtex-string-files
+
+---------------------------------------------------------
+Entry to this mode calls the value of bibtex-mode-hook if that value is
+non-nil."
+  (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-completion-candidates bibtex-predefined-strings)
+  (mapcar
+   (function
+    (lambda (filename)
+      ;; collect pathnames
+      (let* ((bib (getenv "BIBINPUTS"))
+             (path (if bib
+                       bib
+                     "."))
+             (dirs
+              (mapcar
+               (function
+                (lambda (dirname)  ;; strips off trailing slashes
+                  (let ((len (length dirname)))
+                    (if (equal (elt dirname (1- len)) "/")
+                        (substring dirname 0 (1- (1- len)))
+                      dirname))))
+               (let (actdirs)
+                 (while (string-match ":" path)
+                   (setq actdirs
+                         (append actdirs
+                                 (list (substring
+                                        path 0
+                                        (1- (match-end 0)))))
+                         path (substring path (match-end 0))))
+                 (append actdirs (list 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 ((curbuf (current-buffer))
+                  (bufname (make-temp-name ""))
+                  (compl bibtex-completion-candidates))
+              (create-file-buffer bufname)
+              (set-buffer bufname)
+              (insert-file-contents fullfilename)
+              (goto-char (point-min))
+              (while (search-forward-regexp bibtex-string nil t)
+                (setq
+                 compl
+                 (append
+                  compl
+                  (list
+                   (list (buffer-substring
+                          (match-beginning bibtex-name-in-string)
+                          (match-end bibtex-name-in-string)))))))
+              (kill-buffer bufname)
+              (set-buffer curbuf)
+              (setq bibtex-completion-candidates compl))
+          (error "File %s not in $BIBINPUTS paths" filename)))))
+   bibtex-string-files)
+  (make-local-variable 'paragraph-start)
+  (setq paragraph-start "^[ \f\n\t]*$")
+  (make-local-variable 'comment-start)
+  (setq comment-start "%")
+  (auto-fill-mode 1)			; nice alignments
+  (setq left-margin (+ bibtex-text-alignment 1))
+  (run-hooks 'bibtex-mode-hook))
+
+(defun bibtex-entry (entry-type &optional required optional)
+  (interactive (let* ((completion-ignore-case t)
+		      (e-t (completing-read
+                            "Entry Type: "
+                            bibtex-entry-field-alist
+                            nil t)))
+		 (list e-t)))
+  (if (and (null required) (null optional))
+      (let* ((e (assoc-ignore-case entry-type bibtex-entry-field-alist))
+	     (r-n-o (elt e 1))
+	     (c-ref (elt e 2)))
+	(if (null 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)))))
+  (let*
+      (labels
+       label
+       (case-fold-search t)
+       (key
+        (if bibtex-maintain-sorted-entries
+            (progn
+              (save-excursion
+                (goto-char (point-min))
+                (while
+                    (re-search-forward
+                     "\\(^@[a-z]+[ \t\n]*[{(][ \t\n]*\\([^ ,\t\n]+\\)[ \t\n]*,\\)\\|\\(^[ \t\n]*crossref[ \t\n]*=[ \t\n]*[{\"]\\([^ ,\t\n]*\\)[}\"],$\\)"
+                     nil t)
+                  (if (match-beginning 2)
+                      (setq label (buffer-substring 
+                                   (match-beginning 2) (match-end 2)))
+                    (setq label (buffer-substring
+                                 (match-beginning 4) (match-end 4))))
+                  (if (not (assoc label labels))
+                      (setq labels
+                            (cons (list label) labels)))))
+              (completing-read
+               (format "%s key: " entry-type)
+               labels)))))
+    (if key
+	(bibtex-find-entry-location key))	
+    (bibtex-move-outside-of-entry)
+    (insert "@" entry-type "{")
+    (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
+	  (bibtex-make-optional-field '("key")))
+      (mapcar 'bibtex-make-optional-field optional)
+      (mapcar 'bibtex-make-optional-field 
+	      bibtex-mode-user-optional-fields)
+      (if bibtex-include-OPTannote
+	  (bibtex-make-optional-field '("annote")))
+      (insert "\n}\n\n"))
+    (if key
+	(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* ((pnt (point))
+         (field-name
+          (progn
+            (beginning-of-line)
+            (condition-case errname
+                (bibtex-enclosing-regexp bibtex-field)
+              (search-failed
+               (goto-char pnt)
+               (error "Not on BibTeX field")))
+            (re-search-backward
+             "^[ \t]*\\([A-Za-z]+\\)[ \t\n]*=" nil t)
+            (let ((mb (match-beginning 1))
+                  (me (match-end 1)))
+              (buffer-substring
+               (if (looking-at "^[ \t]*OPT")
+                   (+ 3 mb)
+                 mb)
+               me))))
+         (reference-type
+          (progn
+            (re-search-backward
+             "^@\\([A-Za-z]+\\)[ \t\n]*[{(][^, \t\n]*[ \t\n]*," nil t)
+            (buffer-substring (match-beginning 1) (match-end 1))))
+         (entry-list
+          (assoc-ignore-case reference-type
+                               bibtex-entry-field-alist))
+         (c-r-list (elt entry-list 2))
+         (req-opt-list
+          (if (and
+               (member reference-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-mode-user-optional-fields
+                           (if (member
+                                reference-type
+                                bibtex-include-OPTcrossref)
+                               '(("crossref"
+                                  "Label of the crossreferenced entry")))
+                           (if bibtex-include-OPTannote
+                               '(("annote"
+                                  "Personal annotation (ignored)")))
+                           (if bibtex-include-OPTkey
+                               '(("key"
+                                  "Key used for label creation if author and editor fields are missing"))))))
+    (goto-char pnt)
+    (if (assoc field-name list-of-entries)
+        (message (elt (assoc field-name list-of-entries) 1))
+      (message "NO COMMENT AVAILABLE"))))
+
+(defun bibtex-make-field (e-t)
+  "Makes a field named E-T in current BibTeX entry."
+  (interactive "sBibTeX entry type: ")
+  (let ((name  (elt e-t 0)))
+    (insert ",\n")
+    (indent-to-column bibtex-name-alignment)
+    (insert name " = ")
+    (indent-to-column bibtex-text-alignment)
+    (insert bibtex-field-left-delimiter bibtex-field-right-delimiter)))
+
+(defun bibtex-make-optional-field (e-t)
+  "Makes an optional field named E-T in current BibTeX entry."
+  (interactive "sOptional BibTeX entry type: ")
+  (if (consp e-t)
+      (setq e-t (cons (concat "OPT" (car e-t)) (cdr e-t)))
+    (setq e-t (concat "OPT" e-t)))
+  (bibtex-make-field e-t))
+
+(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."
+  (interactive)
+  (re-search-backward "^@" 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 next entry."
+  (interactive)
+  ;; if point was previously at the end of an entry, this puts us
+  ;; inside the next entry, otherwise we remain in the current one.
+  (progn
+    (skip-whitespace-and-comments)
+    (end-of-line))
+  (bibtex-beginning-of-entry)
+  (let ((parse-sexp-ignore-comments t))
+    (forward-sexp) ; skip entry type
+    (forward-sexp) ; skip entry body
+    ))
+  
+(defun bibtex-ispell-entry ()
+  "Spell whole BibTeX entry."
+  (interactive)
+  (ispell-region (progn (bibtex-beginning-of-entry) (point))
+		 (progn (bibtex-end-of-entry) (point))))
+
+(defun bibtex-ispell-abstract ()
+  "Spell abstract of BibTeX entry."
+  (interactive)
+  (let ((pnt (bibtex-end-of-entry)))
+    (bibtex-beginning-of-entry)
+    (if (null
+         (re-search-forward "^[ \t]*[OPT]*abstract[ \t]*=" pnt))
+        (error "No abstract in entry.")))
+  (ispell-region (point)
+		 (save-excursion (forward-sexp) (point))))
+
+(defun bibtex-narrow-to-entry ()
+  "Narrow buffer to current BibTeX entry."
+  (interactive)
+  (save-excursion
+    (narrow-to-region (progn (bibtex-beginning-of-entry) (point))
+		      (progn (bibtex-end-of-entry) (point)))))
+
+
+(defun bibtex-hide-entry-bodies (&optional arg)
+  "Hide all lines between first and last BibTeX entries not beginning with @.
 With argument, show all text."
   (interactive "P")
   (save-excursion
@@ -804,319 +1454,139 @@
       (setq selective-display (not arg))
       (set-buffer-modified-p modifiedp))))
 
-(defvar bibtex-sort-ignore-string-entries nil
-  "*If true, bibtex @STRING entries are ignored when determining ordering
-of the buffer (e.g. sorting, locating alphabetical position for new entries,
-etc.)")
-
-(defun sort-bibtex-entries ()
-  "Sort bibtex entries alphabetically by key.
-Text before the first bibtex entry, and following the last is not affected.
+(defun bibtex-sort-entries ()
+  "Sort BibTeX entries alphabetically by key.
+Text before the first BibTeX entry, and following the last is not affected.
 If bibtex-sort-ignore-string-entries is true, @string entries will be ignored.
 
 Bugs:
-  1. Text between the closing brace ending one bibtex entry, and the @ starting 
+  1. Text between the closing brace ending one BibTeX entry, and the @ starting
      the next, is considered part of the PRECEDING entry.  Perhaps it should be
      part of the following entry."
   (interactive)
   (save-restriction
     (beginning-of-first-bibtex-entry)
-    (narrow-to-region (point)
-		      (save-excursion
-			(goto-char (point-max))
-			(beginning-of-bibtex-entry)
-			(end-of-bibtex-entry)
-			(point)))
-    (sort-subr nil			; reversep
-	       ;; beginning of record function
-	       'forward-line
-	       ;; end of record function
-	       (function (lambda () (and (re-search-forward "}\\s-*\n[\n \t]*@" nil 'move)
-					 (forward-char -2))))
-	       ;; start of key function
-	       (if bibtex-sort-ignore-string-entries
-		   (function (lambda ()
-			       (while (and (re-search-forward "^\\s-*\\([@a-zA-Z]*\\)\\s-*{\\s-*")
-					   (string-equalp "@string"
-							  (buffer-substring (match-beginning 1)
-									    (match-end 1)))))
-			       nil))
-		   (function (lambda () (re-search-forward "{\\s-*") nil)))
-	       ;; end of key function
-	       (function (lambda () (search-forward ",")))
-	       )))
+    (narrow-to-region
+     (point)
+     (save-excursion
+       (goto-char (point-max))
+       (bibtex-beginning-of-entry)
+       (bibtex-end-of-entry)
+       (point)))
+    (sort-subr
+     nil
+     ;; NEXTREC function
+     'forward-line
+     ;; ENDREC function
+     (function
+      (lambda ()
+        (and
+         (re-search-forward "}\\s-*\n[\n \t]*@" nil 'move)
+         (forward-char -2))))
+     ;; STARTKEY function
+     (if bibtex-sort-ignore-string-entries
+         (function
+          (lambda ()
+            (while
+                (and
+                 (re-search-forward "^\\s-*\\([@a-zA-Z]*\\)\\s-*{\\s-*")
+                 (string-equal
+                  "@string"
+                  (downcase
+                   (buffer-substring
+                    (match-beginning 1)
+                    (match-end 1))))))
+            nil))
+       (function
+        (lambda ()
+          (re-search-forward "{\\s-*"))))
+     ;; ENDKEY function
+     (function
+      (lambda ()
+        (search-forward ","))))))
   
-(defun map-bibtex-entries (fun)
-  "Call FUN for each bibtex entry starting with the current, 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 true, FUN will not be called for @string entries."
-  (beginning-of-bibtex-entry)
-  (while (re-search-forward "^@[^{]*{[ \t]*\\([^, ]*\\)" nil t)
-    (if (and bibtex-sort-ignore-string-entries
-	     (string-equalp "@string{"
-			    (buffer-substring (match-beginning 0)
-					      (match-beginning 1))))
-	nil ; ignore the @string entry.
-      (funcall fun (buffer-substring (match-beginning 1) (match-end 1))))))
-  
-(defun find-bibtex-entry-location (entry-name)
-  "Searches from beginning of current buffer looking for place to put the
-bibtex entry named ENTRY-NAME.  Buffer is assumed to be in sorted order,
-without duplicates (see \\[sort-bibtex-entries]), if it is not, an error will
-be signalled."
+(defun bibtex-find-entry-location (entry-name &optional maybedup)
+  "Looking for place to put the BibTeX entry named ENTRY-NAME.
+Searches from beginning of buffer. Buffer is assumed to be in sorted
+order, without duplicates (see \\[bibtex-sort-entries]), if it is not,
+an error will be signalled. If optional argument MAYBEDUP is non-nil
+no error/warning messages about ENTRY-NAME being a (potential)
+duplicate of an existing entry will be emitted. This function returns
+`nil' if ENTRY-NAME is a duplicate of an existing entry and t in all
+other cases."
   (interactive "sBibtex entry key: ")
-  (let ((previous nil)
+  (let ((nodup t)
+        (previous nil)
 	point)
     (beginning-of-first-bibtex-entry)
-    (or (catch 'done
-	  (map-bibtex-entries (function (lambda (current)
-				 (cond
-				  ((string-equal entry-name current)
-				   (error "Entry duplicates existing!"))
-				  ((or (null previous)
-				       (string< previous current))
-				   (setq previous current
-					 point (point))
-				   (if (string< entry-name current)
-				       (progn
-					 (beginning-of-bibtex-entry)
-					 ;; Many schemes append strings to
-					 ;; existing entries to resolve them,
-					 ;; so initial substring matches may
-					 ;; indicate a duplicate entry.  
-					 (let ((idx (string-match (regexp-quote entry-name) current)))
-					   (if (and (integerp idx)
-						    (zerop idx))
-					       (progn
-						 (message "Warning: Entry %s may be a duplicate of %s!"
-							  entry-name current)
-						 (ding t))))
-					 (throw 'done t))))
-				  ((string-equal previous current)
-				   (error "Duplicate here with previous!"))
-				  (t (error "Entries out of order here!")))))))
-	(end-of-bibtex-entry))))
-
-(defun validate-bibtex-buffer ()
-  "Find some typical errors in bibtex files.
-  1. At signs (@) not as first char of a line.
-  2. Double quotes (\") inside strings.
-  3. Closing braces (}) not the last character of a line."
-  (interactive)
-  (let ((point (point)))
-    (while (re-search-forward ".@" nil t)
-      (let* ((foo (parse-partial-sexp (save-excursion (beginning-of-bibtex-entry)
-						      (point))
-				      (point)))
-	     (in-a-string (nth 3 foo)))
-	(if (not in-a-string)
-	    (error "At sign (@) out of place!"))))
-    (goto-char point)
-    (while (search-forward "\"" nil t)
-      (or (looking-at "[,}][ \t]*$")
-	  (char-equal (preceding-char) ?\")
-	  ;; some versions put closing brace on separate line.
-	  (looking-at "[ \t]*\n}")
-	  (save-excursion
-	    (save-restriction
-	      (narrow-to-region (point)
-				(progn (beginning-of-line) (point)))
-	      (looking-at "^[ \t]*[a-zA-Z]+[ \t]*=[ \t]*\"$")))
-	  (error "Quote out of place, or missing \",\" or \"}\"!")))
-    (goto-char point)
-    ;; This is only approximate, should actually search for close braces,
-    ;; then see if they are inside a string, or at the end of a line.
-    ;; This just gets the typical case of whitespace after a closing brace.
-    (while (search-forward "}[ \t]+$" nil t)
-      (error "Brace not last char of line!"))
-    (goto-char point)
-    (message "Bibtex buffer appears o.k.")))
-
-(defun find-bibtex-duplicates ()
-  "Searches forward in current buffer looking for duplicate bibtex entries.
-Buffer is assumed to be sorted, see \\[sort-bibtex-entries]"
-  (interactive)
-  (let ((point (point)))
-    ;; errors if things are not right...
-    (find-bibtex-entry-location (make-string 10 255))
-    (goto-char point)
-    (message "No duplicates found!")))
-
-
-;;; assoc doesn't ignore case, so we need an assoc that does...
-(defun assoc-string-equalp (thing alist)
-  (or (assoc thing alist)
-      (while (and alist
-		  (not (string-equalp thing (car (car alist)))))
-	(setq alist (cdr alist)))
-      (car alist)))
-
-(defvar bibtex-maintain-sorted-entries nil
-  "*If true, bibtex-mode will attempt to maintain all bibtex entries in 
-sorted order.  
-
-Note that this is more a property of a file than a personal preference and
-as such should normally be set via a file local variable entry.")
+    (or
+     (catch 'done
+       (map-bibtex-entries
+        (function
+         (lambda (current)
+           (cond ((string-equal entry-name current)
+                  (setq nodup nil)
+                  (bibtex-beginning-of-entry)
+                  (if maybedup
+                      (throw 'done t)
+                    (error "Entry duplicates existing!")))
+                 ((or (null previous)
+                      (string< previous current))
+                  (setq previous current
+                        point (point))
+                  (if (string< entry-name current)
+                      (progn
+                        (bibtex-beginning-of-entry)
+                        ;; Many schemes append strings to
+                        ;; existing entries to resolve them,
+                        ;; so initial substring matches may
+                        ;; indicate a duplicate entry.  
+                        (let ((idx
+                               (string-match
+                                (regexp-quote entry-name) current)))
+                          (if (and
+                               (integerp idx)
+                               (zerop idx)
+                               (not maybedup)
+                               (not (equal entry-name "")))
+                              (progn
+                                (message
+                                 "Warning: Entry %s may be a duplicate of %s!"
+                                 entry-name current)
+                                (ding t))))
+                        (throw 'done t))))
+                 ((string-equal previous current)
+                  (error "Duplicate here with previous!"))
+                 (t (error "Entries out of order here!")))))))
+     (goto-char (point-max)))
+    nodup))
 
-(defun bibtex-entry (entry-type &optional required optional)
-  (interactive (let* ((completion-ignore-case t)
-		      (e-t (completing-read "Entry Type: " bibtex-entry-field-alist
-					    nil t)))
-		 (list e-t)))
-  (if (and (null required) (null optional))
-      (let* ((e (assoc-string-equalp entry-type bibtex-entry-field-alist))
-	     (r-n-o (elt e 1))
-	     (c-ref (elt e 2)))
-	(if (null e)
-	  (error "Bibtex entry type %s not defined!"))
-	(if (and 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)))))
-  (let ((key (if bibtex-maintain-sorted-entries
-		 (read-string (format "%s key: " entry-type)))))
-    (if key
-	(find-bibtex-entry-location key))	
-    (bibtex-move-outside-of-entry)
-    (insert "@" entry-type "{")
-    (if key
-	(insert key))
-    (save-excursion
-      (mapcar 'bibtex-make-field required)
-      (if bibtex-include-OPTcrossref
-	  (bibtex-make-optional-field "crossref"))
-      (if bibtex-include-OPTkey
-	  (bibtex-make-optional-field "key"))
-      (mapcar 'bibtex-make-optional-field optional)
-      (mapcar 'bibtex-make-optional-field 
-	      bibtex-mode-user-optional-fields)
-      (if bibtex-include-OPTannote
-	  (bibtex-make-optional-field "annote"))
-      (insert "\n}\n\n"))
-    (if key
-	(bibtex-next-field t))
-    (run-hooks 'bibtex-add-entry-hook)))
-
-;; (defun bibtex-entry (entry-type required optional)
-;;   (bibtex-move-outside-of-entry)
-;;   (insert (concat "@" entry-type "{,\n\n}\n\n"))
-;;   (previous-line 3)
-;;   (insert (mapconcat 'bibtex-make-entry required ",\n"))
-;;   (if required
-;;       (if optional
-;; 	  (insert ",\n")))
-;;   (insert (mapconcat 'bibtex-make-OPT-entry optional ",\n"))
-;;   (if bibtex-mode-user-optional-fields		;MON...
-;;       (progn
-;; 	(if optional
-;; 	    (insert ",\n"))
-;; 	(insert (mapconcat 'bibtex-make-OPT-entry
-;; 			   bibtex-mode-user-optional-fields
-;; 			   ",\n"))))		;MON
-;;  (up-list -1)
-;;  (forward-char 1))
-
-
-(defun bibtex-make-field (e-t)
-  (interactive "sBibTeX entry type: ")
-  (let ((name  (if (consp e-t) (car e-t) e-t))
-	(value (if (consp e-t) (cdr e-t) "")))
-    (insert ",\n")
-    (indent-to-column bibtex-name-alignment)
-    (insert name " = ")
-    (indent-to-column bibtex-text-alignment)
-    ;; lucid emacs prin1-to-string breaks the undo chain.  When they fix
-    ;; that, the  hack can be removed. [alarson:19930316.0805CST]
-;    (insert (prin1-to-string value))
-    ;; begin hack
-    (insert (format (if (stringp value) "\"%s\"" "%s")
-		    value))
-    ;; end hack
-    nil))
+(defun bibtex-validate-buffer ()
+  "Validate if the current BibTeX buffer is syntactically correct.
+Any garbage (e.g. comments) before the first \"@\" is not tested (so
+you can put comments here)."
+  (interactive)
+  (let ((pnt (point))
+        (max (point-max)))
+    (goto-char (point-min))
+    (while (< (re-search-forward "@\\|\\'") max)
+      (forward-char -1)
+      (let ((p (point)))
+        (if (looking-at "@string")
+            (forward-char)
+          (if (not (and
+                    (re-search-forward bibtex-reference nil t)
+                    (equal p (match-beginning 0))))
+              (progn
+                (goto-char p)
+                (error "Bad entry begins here"))))))
+    (bibtex-find-entry-location (make-string 10 255))
+    ;; find duplicates
+    (goto-char pnt)
+    (message "BibTeX buffer is syntactically correct")))
 
-(defun bibtex-make-optional-field (e-t)
-  (interactive "sOptional BibTeX entry type: ")
-  (if (consp e-t)
-      (setq e-t (cons (concat "OPT" (car e-t)) (cdr e-t)))
-    (setq e-t (concat "OPT" e-t)))
-  (bibtex-make-field e-t))
-
-;; What to do about crossref?  if present, journal and year are 
-;; both optional.  Due to this, i move all of them into optional. -- MON
-
-(defun bibtex-Article ()
-  (interactive)
-  (bibtex-entry "Article"))
-
-(defun bibtex-Book ()
-  (interactive)
-  (bibtex-entry "Book"))
-
-(defun bibtex-Booklet ()
-  (interactive)
-  (bibtex-entry "Booklet"))
-
-;(defun bibtex-DEAthesis ()
-;  (interactive)
-;  (bibtex-entry "DEAthesis"))
-
-(defun bibtex-InBook ()
-  (interactive)
-  (bibtex-entry "InBook"))
-
-(defun bibtex-InCollection ()
-  (interactive)
-  (bibtex-entry "InCollection"))
-
-(defun bibtex-InProceedings ()
-  (interactive)
-  (bibtex-entry "InProceedings"))
-
-(defun bibtex-Manual ()
-  (interactive)
-  (bibtex-entry "Manual"))
-
-(defun bibtex-MastersThesis ()
-  (interactive)
-  (bibtex-entry "MastersThesis"))
-
-(defun bibtex-Misc ()
-  (interactive)
-  (bibtex-entry "Misc"))
-
-(defun bibtex-PhdThesis ()
-  (interactive)
-  (bibtex-entry "PhdThesis"))
-
-(defun bibtex-Proceedings ()
-  (interactive)
-  (bibtex-entry "Proceedings"))
-
-(defun bibtex-TechReport ()
-  (interactive)
-  (bibtex-entry "TechReport"))
-
-(defun bibtex-Unpublished ()
-  (interactive)
-  (bibtex-entry "Unpublished"))
-
-(defun bibtex-string ()
-  (interactive)
-  (bibtex-move-outside-of-entry)
-  (insert "@string{ = \"\"}\n")
-  (previous-line 1)
-  (forward-char 8))
-
-(defun bibtex-preamble ()
-  (interactive)
-  (bibtex-move-outside-of-entry)
-  (insert "@Preamble{}\n")
-  (previous-line 1)
-  (forward-char 10))
-
 (defun bibtex-next-field (arg)
-  "Finds end of text of next BibTeX field; with arg, to its beginning"
+  "Finds end of text of next BibTeX field; with arg, to its beginning."
   (interactive "P")
   (bibtex-inside-field)
   (let ((start (point)))
@@ -1131,17 +1601,6 @@
        (forward-char 1))))
   (bibtex-find-text arg))
 
-;; (defun bibtex-next-field ()
-;;   "Finds end of text of next field."
-;;   (interactive)
-;;   (condition-case ()
-;;       (progn
-;; 	(bibtex-inside-field)
-;; 	(re-search-forward ",[ \t\n]*" (point-max) 1)
-;; 	(bibtex-enclosing-field)
-;; 	(bibtex-inside-field))
-;;     (error nil)))
-
 (defun bibtex-find-text (arg)
   "Go to end of text of current field; with arg, go to beginning."
   (interactive "P")
@@ -1150,25 +1609,16 @@
   (if arg
       (progn
 	(goto-char (match-beginning bibtex-text-in-field))
-	(if (looking-at "\"")
+	(if (looking-at bibtex-field-left-delimiter)
 	    (forward-char 1)))
     (goto-char (match-end bibtex-text-in-field))
-    (if (= (preceding-char) ?\")
-	(forward-char -1))))
-
-;; (defun bibtex-find-text ()
-;;   "Go to end of text of current field."
-;;   (interactive)
-;;   (condition-case ()
-;;       (progn
-;; 	(bibtex-inside-field)
-;; 	(bibtex-enclosing-field)
-;; 	(goto-char (match-end bibtex-text-in-field))
-;; 	(bibtex-inside-field))
-;;     (error nil)))
+    (if (= (preceding-char) (aref bibtex-field-right-delimiter 0))
+	(forward-char -1)))
+  (if bibtex-help-message
+      (bibtex-print-help-message)))
 
 (defun bibtex-remove-OPT ()
-  "Removes the 'OPT' starting optional arguments and goes to end of text"
+  "Removes the 'OPT' starting optional arguments and goes to end of text."
   (interactive)
   (bibtex-inside-field)
   (bibtex-enclosing-field)
@@ -1183,18 +1633,8 @@
  	  (indent-to-column bibtex-text-alignment))))
   (bibtex-inside-field))
 
-(defun bibtex-inside-field ()
-  "Try to avoid point being at end of a bibtex field."
-  (interactive)
-  (end-of-line)
-  (skip-chars-backward " \t")		;MON - maybe delete these chars?
-  (cond ((= (preceding-char) ?,)
-	 (forward-char -2))) ; -1 --> -2 sct@dcs.edinburgh.ac.uk
-  (cond ((= (preceding-char) ?\")
-	 (forward-char -1))))		;MON - only go back if quote
-
-(defun bibtex-remove-double-quotes ()
-  "Removes \"\" around string."
+(defun bibtex-remove-double-quotes-or-braces ()
+  "Removes \"\" or {} around string."
   (interactive)
   (save-excursion
     (bibtex-inside-field)
@@ -1203,14 +1643,14 @@
 	  (stop (match-end  bibtex-text-in-field)))
       (goto-char stop)
       (forward-char -1)
-      (if (looking-at "\"")
+      (if (looking-at bibtex-field-right-delimiter)
 	  (delete-char 1))
       (goto-char start)
-      (if (looking-at "\"")
+      (if (looking-at bibtex-field-left-delimiter)
 	  (delete-char 1)))))
 
 (defun bibtex-kill-optional-field ()
-  "Kill the entire enclosing optional BibTeX field"
+  "Kill the entire enclosing optional BibTeX field."
   (interactive)
   (bibtex-inside-field)
   (bibtex-enclosing-field)
@@ -1225,16 +1665,16 @@
       (error "Mandatory fields can't be killed"))))
 
 (defun bibtex-empty-field ()
-  "Delete the text part of the current field, replace with empty text"
+  "Delete the text part of the current field, replace with empty text."
   (interactive)
   (bibtex-inside-field)
   (bibtex-enclosing-field)
   (goto-char (match-beginning bibtex-text-in-field))
   (kill-region (point) (match-end bibtex-text-in-field))
-  (insert "\"\"")
+  (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 text of similar field in previous entry.
 With arg, go up ARG entries.  Repeated, goes up so many times.  May be
@@ -1258,7 +1698,6 @@
 				  (point))
 				stop-name)
 	      bibtex-field-text)))
-	
 	; if executed several times in a row, start each search where the
 	; last one finished
 	(cond ((or (eq last-command 'bibtex-pop-previous)
@@ -1267,16 +1706,37 @@
 	       )
 	      (t
 	       (bibtex-enclosing-reference)
-	       (setq bibtex-pop-previous-search-point (match-beginning 0))
+	       (setq bibtex-pop-previous-search-point (point))
 	       (setq bibtex-pop-next-search-point (match-end 0))))
 	(goto-char bibtex-pop-previous-search-point)
-	
 	; Now search for arg'th previous similar field
 	(cond
 	 ((re-search-backward matching-entry (point-min) t arg)
 	  (setq new-text
 		(buffer-substring (match-beginning bibtex-text-in-cfield)
 				  (match-end bibtex-text-in-cfield)))
+          ;; change delimiters, if any changes needed
+          (cond
+           ((and
+             (equal bibtex-field-left-delimiter "{")
+             (eq (aref new-text 0) ?\")
+             (eq (aref new-text (1- (length new-text))) ?\"))
+            (aset new-text 0 ?\{)
+            (aset new-text (1- (length new-text)) ?\}))
+           ((and
+             (equal bibtex-field-left-delimiter "\"")
+             (eq (aref new-text 0) ?\{)
+             (eq (aref new-text (1- (length new-text))) ?\}))
+            (aset new-text 0 ?\")
+            (aset new-text (1- (length new-text)) ?\"))
+           ((or
+             (not (eq (aref new-text 0)
+                      (aref bibtex-field-left-delimiter 0)))
+             (not (eq (aref new-text (1- (length new-text)))
+                      (aref bibtex-field-right-delimiter 0))))
+            (setq new-text (concat bibtex-field-left-delimiter
+                                   new-text 
+                                   bibtex-field-right-delimiter))))
 	  ; Found a matching field. Remember boundaries.
 	  (setq bibtex-pop-next-search-point (match-end 0))
 	  (setq bibtex-pop-previous-search-point (match-beginning 0))
@@ -1322,7 +1782,7 @@
 	       )
 	      (t
 	       (bibtex-enclosing-reference)
-	       (setq bibtex-pop-previous-search-point (match-beginning 0))
+	       (setq bibtex-pop-previous-search-point (point))
 	       (setq bibtex-pop-next-search-point (match-end 0))))
 	(goto-char bibtex-pop-next-search-point)
 	
@@ -1332,6 +1792,28 @@
 	  (setq new-text
 		(buffer-substring (match-beginning bibtex-text-in-cfield)
 				  (match-end bibtex-text-in-cfield)))
+          ;; change delimiters, if any changes needed
+          (cond
+           ((and
+             (equal bibtex-field-left-delimiter "{")
+             (eq (aref new-text 0) ?\")
+             (eq (aref new-text (1- (length new-text))) ?\"))
+            (aset new-text 0 ?\{)
+            (aset new-text (1- (length new-text)) ?\}))
+           ((and
+             (equal bibtex-field-left-delimiter "\"")
+             (eq (aref new-text 0) ?\{)
+             (eq (aref new-text (1- (length new-text))) ?\}))
+            (aset new-text 0 ?\")
+            (aset new-text (1- (length new-text)) ?\"))
+           ((or
+             (not (eq (aref new-text 0)
+                      (aref bibtex-field-left-delimiter 0)))
+             (not (eq (aref new-text (1- (length new-text)))
+                      (aref bibtex-field-right-delimiter 0))))
+            (setq new-text (concat bibtex-field-left-delimiter
+                                   new-text 
+                                   bibtex-field-right-delimiter))))
 	  ; Found a matching field. Remember boundaries.
 	  (setq bibtex-pop-next-search-point (match-end 0))
 	  (setq bibtex-pop-previous-search-point (match-beginning 0))
@@ -1344,259 +1826,303 @@
 	  (error "No next matching BibTeX field."))))))
   (setq this-command 'bibtex-pop-next))
 
-(defun bibtex-flash-head ()
-  "Flash at BibTeX reference head before point, if exists.  (Moves point)."
-  (let ((flash))
-    (cond ((re-search-backward bibtex-reference-head (point-min) t)
-	   (goto-char (match-beginning bibtex-type-in-head))
-	   (setq flash (match-end bibtex-key-in-reference)))
-	  (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-clean-entry (&optional arg)
+  "Finish editing the current BibTeX entry and clean it up.
+For all optional fields of current BibTeX entry: if empty, kill the
+whole field; otherwise, remove the \"OPT\" string in the name; if text
+numerical, remove double-quotes. For all mandatory fields: if empty,
+signal error. If label of entry is empty or a prefix argument was
+given, calculate a new entry label."
+  (interactive "P")
+  (bibtex-beginning-of-entry)
+  (let ((start (point))
+        crossref-there)
+    (save-restriction
+      (narrow-to-region start (save-excursion (bibtex-end-of-entry) (point)))
+      (while (and
+              (re-search-forward bibtex-field (point-max) t 1)
+              (not crossref-there))
+        ;; determine if reference has crossref entry
+	(let ((begin-name (match-beginning bibtex-name-in-field))
+	      (begin-text (match-beginning bibtex-text-in-field)))
+	  (goto-char begin-name)
+          (if (looking-at "\\(OPTcrossref\\)\\|\\(crossref\\)")
+              (progn
+                (goto-char begin-text)
+                (if (not (looking-at
+                          (concat
+                           bibtex-field-left-delimiter
+                           bibtex-field-right-delimiter)))
+                    (setq crossref-there t))))))
+      (bibtex-enclosing-reference)
+      (re-search-forward bibtex-reference-type)
+      (let ((begin-type (1+ (match-beginning 0)))
+            (end-type (match-end 0)))
+        (goto-char start)
+        (while (re-search-forward bibtex-field (point-max) t 1)
+          (let ((begin-field (match-beginning 0))
+                (end-field (match-end 0))
+                (begin-name (match-beginning bibtex-name-in-field))
+                (end-name (match-end  bibtex-name-in-field))
+                (begin-text (match-beginning bibtex-text-in-field))
+                (end-text (match-end bibtex-text-in-field))
+                )
+            (goto-char begin-name)
+            (cond ((and
+                    (looking-at "OPT")
+                    bibtex-clean-entry-zap-empty-opts)
+                   (goto-char begin-text)
+                   (if (looking-at
+                        (concat
+                         bibtex-field-left-delimiter
+                         bibtex-field-right-delimiter))
+                       ;; empty: delete whole field if really optional
+                       ;; (missing crossref handled) or complain
+                       (if (and
+                            (not crossref-there)
+                            (assoc
+                             (downcase
+                              (buffer-substring
+                               (+ (length "OPT") begin-name) end-name))
+                             (car (car (cdr
+                                        (assoc-ignore-case
+                                         (buffer-substring begin-type end-type)
+                                         bibtex-entry-field-alist))))))
+                           ;; field is not really optional
+                           (progn
+                             (goto-char begin-name)
+                             (delete-char (length "OPT"))
+                             ;; make field non-OPT
+                             (search-forward "=")
+                             (delete-horizontal-space)
+                             (indent-to-column bibtex-text-alignment)
+                             (forward-char)
+                             ;; and loop to go through next test
+                             (error "Mandatory field ``%s'' is empty"
+                                    (buffer-substring begin-name
+                                                      end-name)))
+                         ;; field is optional
+                         (delete-region begin-field end-field))
+                     ;; otherwise: not empty, delete "OPT"
+                     (goto-char begin-name)
+                     (delete-char (length "OPT"))
+                     (progn
+                       ;; fixup alignment. [alarson:19920309.2047CST]
+                       (search-forward "=")
+                       (delete-horizontal-space)
+                       (indent-to-column bibtex-text-alignment))
+                     (goto-char begin-field) ; and loop to go through next test
+                     ))
+                  (t
+                   (goto-char begin-text)
+                   (cond ((looking-at (concat
+                                       bibtex-field-left-delimiter
+                                       "[0-9]+"
+                                       bibtex-field-right-delimiter))
+                          ;; if numerical,
+                          (goto-char end-text)
+                          (delete-char -1) ; delete enclosing double-quotes
+                          (goto-char begin-text)
+                          (delete-char 1)
+                          (goto-char end-field) ; go to end for next search
+                          (forward-char -2) ; to compensate for the 2 quotes deleted
+                          )
+                         ((looking-at (concat
+                                       bibtex-field-left-delimiter
+                                       bibtex-field-right-delimiter))
+                          ;; if empty quotes, complain
+                          (forward-char 1)
+                          (if (not (or (equal (buffer-substring
+                                               begin-name
+                                               (+ begin-name 3))
+                                              "OPT")
+                                       (equal (buffer-substring
+                                               begin-name
+                                               (+ begin-name 3))
+                                              "opt")))
+                              (error "Mandatory field ``%s'' is empty"
+                                     (buffer-substring begin-name end-name))))
+                         (t
+                          (goto-char end-field)))))))))
+    (goto-char start)
+    (bibtex-end-of-entry)
+    ;; sct@dcs.edinburgh.ac.uk
+    (save-excursion
+      (forward-line -1)
+      (end-of-line)
+      (if (eq (preceding-char) ?,)
+ 	  (backward-delete-char 1)))
+    (skip-whitespace-and-comments))
+  (let* ((eob (progn
+                (bibtex-beginning-of-entry)
+                (bibtex-end-of-entry)
+                (point)))
+         (key (progn
+                (bibtex-beginning-of-entry)
+                (if (search-forward-regexp
+                     bibtex-reference-head eob t)
+                    (buffer-substring
+                     (match-beginning bibtex-key-in-head)
+                     (match-end bibtex-key-in-head))))))
+    (if (or
+         arg
+         (not key))
+        (progn
+          (let ((autokey
+                 (if bibtex-autokey-edit-before-use
+                     (read-from-minibuffer "Key to use: "
+                                           (bibtex-generate-autokey))
+                   (bibtex-generate-autokey))))
+            (bibtex-beginning-of-entry)
+            (search-forward-regexp "^@[A-Za-z]+[ \t]*[({]\\([^,]*\\)")
+            (delete-region (match-beginning 1)
+                           (match-end 1))
+            (insert autokey)
+            (let ((start (progn
+                           (bibtex-beginning-of-entry)
+                           (point)))
+                  (end (progn
+                         (bibtex-end-of-entry)
+                         (search-forward-regexp "^@" nil 'move)
+                         (beginning-of-line)
+                         (point))))
+              (kill-region start end)
+              (let ((success (bibtex-find-entry-location autokey t)))
+                (yank)
+                (bibtex-beginning-of-entry)
+                (search-forward-regexp bibtex-reference-head)
+                (setq kill-ring (cdr kill-ring))
+                (if (not success)
+                    (error
+                     "Duplicated key (change manually and enter `bibtex-sort-entries')")))))))))
+
+(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."
+  (interactive "*")
+  (let* ((end (point))
+         (beg (save-excursion
+                (re-search-backward "[ \t{\"]")
+                (forward-char 1)
+                (point)))
+         (part-of-word (buffer-substring beg end))
+         (string-list (copy-sequence bibtex-completion-candidates))
+         (case-fold-search t)
+         (completion (save-excursion
+                       (progn
+                         (while (re-search-backward
+                                 "@string[ \t\n]*{" (point-min) t)
+                           (goto-char (match-end 0))
+                           (let ((pnt (point))
+                                 (strt (match-beginning 0)))
+                             (re-search-forward "[ \t\n]*="
+                                                (point-max) t)
+                             (goto-char (match-beginning 0))
+                             (setq string-list
+                                   (cons
+                                    (list (buffer-substring pnt (point)))
+                                    string-list))
+                             (goto-char strt)))
+                         (setq string-list
+                               (sort string-list
+                                     (lambda(x y)
+                                       (string-lessp
+                                        (car x)
+                                        (car y)))))
+                         (try-completion part-of-word string-list)))))
+    (cond ((eq completion t)
+           (bibtex-remove-double-quotes-or-braces))
+          ((null completion)
+           (error "Can't find completion for \"%s\"" part-of-word))
+          ((not (string= part-of-word completion))
+           (delete-region beg end)
+           (insert completion)
+           (if (assoc completion string-list)
+               (bibtex-remove-double-quotes-or-braces)))
+          (t
+           (message "Making completion list...")
+           (let ((list (all-completions part-of-word string-list)))
+             (with-output-to-temp-buffer "*Completions*"
+               (display-completion-list list)))
+           (message "Making completion list...done")))))
+
+(defun bibtex-Article ()
+  (interactive)
+  (bibtex-entry "Article"))
+
+(defun bibtex-Book ()
+  (interactive)
+  (bibtex-entry "Book"))
+
+(defun bibtex-Booklet ()
+  (interactive)
+  (bibtex-entry "Booklet"))
+
+(defun bibtex-InBook ()
+  (interactive)
+  (bibtex-entry "InBook"))
+
+(defun bibtex-InCollection ()
+  (interactive)
+  (bibtex-entry "InCollection"))
+
+(defun bibtex-InProceedings ()
+  (interactive)
+  (bibtex-entry "InProceedings"))
+
+(defun bibtex-Manual ()
+  (interactive)
+  (bibtex-entry "Manual"))
+
+(defun bibtex-MastersThesis ()
+  (interactive)
+  (bibtex-entry "MastersThesis"))
+
+(defun bibtex-Misc ()
+  (interactive)
+  (bibtex-entry "Misc"))
+
+(defun bibtex-PhdThesis ()
+  (interactive)
+  (bibtex-entry "PhdThesis"))
+
+(defun bibtex-Proceedings ()
+  (interactive)
+  (bibtex-entry "Proceedings"))
+
+(defun bibtex-TechReport ()
+  (interactive)
+  (bibtex-entry "TechReport"))
+
+(defun bibtex-Unpublished ()
+  (interactive)
+  (bibtex-entry "Unpublished"))
+
+(defun bibtex-string ()
+  (interactive)
+  (bibtex-move-outside-of-entry)
+  (insert
+   (concat
+    "@string{ = "
+    bibtex-field-left-delimiter
+    bibtex-field-right-delimiter
+    "}\n"))
+  (forward-line -1)
+  (forward-char 8))
+
+(defun bibtex-preamble ()
+  (interactive)
+  (bibtex-move-outside-of-entry)
+  (insert "@Preamble{}\n")
+  (forward-line -1)
+  (forward-char 10))
 
 
 
-(defun bibtex-enclosing-field ()
-  "Search for BibTeX field enclosing point.
-Point moves to end of field; also, use match-beginning and match-end
-to parse the field."
-  ;; sct@dcs.edinburgh.ac.uk
-  (let ((old-point (point)))
-    (condition-case errname
- 	(bibtex-enclosing-regexp bibtex-field)
-      (search-failed
-       (goto-char old-point)
-       (error "Can't find enclosing BibTeX field.")))))
-
-(defun bibtex-enclosing-reference ()
-  "Search for BibTeX reference enclosing point.
-Point moves to end of reference; also, use match-beginning and match-end
-to parse the reference."
-  ;; sct@dcs.edinburgh.ac.uk
-  (let ((old-point (point)))
-    (condition-case errname
- 	(bibtex-enclosing-regexp bibtex-reference)
-      (search-failed
-       (goto-char old-point)
-       (error "Can't find enclosing BibTeX reference.")))))
-
-(defun bibtex-enclosing-regexp (regexp)
-  "Search for REGEXP enclosing point.
-Point moves to end of REGEXP.  See also match-beginning and match-end.
-If an enclosing REGEXP is not found, signals search-failed; point is left in
-an undefined location.
-
-[Doesn't something like this exist already?]"
-  
-  (interactive "sRegexp: ")
-  ; compute reasonable limits for the loop
-  (let* ((initial (point))
-	 (right (if (re-search-forward regexp (point-max) t)
-		    (match-end 0)
-		  (point-max)))
-	 (left
-	  (progn
-	    (goto-char initial)
-	    (if (re-search-backward regexp (point-min) t)
-		(match-beginning 0)
-	      (point-min)))))
-    ; within the prescribed limits, loop until a match is found
-    (goto-char left)
-    (re-search-forward regexp right nil 1)
-    (if (> (match-beginning 0) initial)
-	(signal 'search-failed (list regexp)))	  
-    (while (<= (match-end 0) initial)
-      (re-search-forward regexp right nil 1)
-      (if (> (match-beginning 0) initial)
-	  (signal 'search-failed (list regexp))))
-    ))
+;;; MAKE BIBTEX a FEATURE
 
-(defun bibtex-clean-entry ()
-  "For all optional fields of current BibTeX entry: if empty, kill the whole field; otherwise, remove the \"OPT\" string in the name; if text numerical, remove double-quotes.  For all mandatory fields: if empty, signal error."
-  (interactive)
-  (beginning-of-bibtex-entry)
-  (let ((start (point)))
-    (save-restriction
-      (narrow-to-region start (save-excursion (end-of-bibtex-entry) (point)))
-      (while (re-search-forward bibtex-field (point-max) t 1)
-	(let ((begin-field (match-beginning 0))
-	      (end-field (match-end 0))
-	      (begin-name (match-beginning bibtex-name-in-field))
-	      (end-name (match-end  bibtex-name-in-field))
-	      (begin-text (match-beginning bibtex-text-in-field))
-	      (end-text (match-end bibtex-text-in-field))
-	      )
-	  (goto-char begin-name)
-	  (cond ((and
-		  (looking-at "OPT")
-		  bibtex-clean-entry-zap-empty-opts)
-		 (goto-char begin-text)
-		 (if (looking-at "\"\"") ; empty: delete whole field
-		     (delete-region begin-field end-field)
-		   ; otherwise: not empty, delete "OPT"
-		   (goto-char begin-name)
-		   (delete-char (length "OPT"))
-		   (progn
-		     ;; fixup alignment. [alarson:19920309.2047CST]
-		     (search-forward "=")
-		     (delete-horizontal-space)
-		     (indent-to-column bibtex-text-alignment))
-		   (goto-char begin-field) ; and loop to go through next test
-		   ))
-		(t
-		 (goto-char begin-text)
-		 (cond ((looking-at "\"[0-9]+\"") ; if numerical,
-			(goto-char end-text)
-			(delete-char -1) ; delete enclosing double-quotes
-			(goto-char begin-text)
-			(delete-char 1)
-			(goto-char end-field) ; go to end for next search
-			(forward-char -2) ; to compensate for the 2 quotes deleted
-			)
-		       ((looking-at "\"\"") ; if empty quotes, complain
-			(forward-char 1)
-			(if (not (or (equal (buffer-substring
-					     begin-name
-					     (+ begin-name 3))
-					    "OPT")
-				     (equal (buffer-substring
-					     begin-name
-					     (+ begin-name 3))
-					    "opt")))
-			    (error "Mandatory field ``%s'' is empty"
-				   (buffer-substring begin-name end-name))))
-		       (t
-			(goto-char end-field))))))))
-    (goto-char start)
-    (end-of-bibtex-entry)
-    ;; sct@dcs.edinburgh.ac.uk
-    (save-excursion
-      (backward-char 1)
-      (skip-syntax-backward " >")
-      (if (eq (preceding-char) ?,)
- 	  (backward-delete-char 1)))
-    (skip-whitespace-and-comments)))
-
-
-;;; Menus for bibtex mode
-
-(define-key bibtex-mode-map [menu-bar entry-types]
-  (cons "Entry Types" (make-sparse-keymap "Entry Types")))
+(provide 'bibtex)
 
-(define-key bibtex-mode-map [menu-bar entry-types bibtex-InProceedings]
-  '(" article in conference Proceedings " . bibtex-InProceedings))
-(define-key bibtex-mode-map [menu-bar entry-types bibtex-Article]
-  '("        Article in journal         " . bibtex-Article))
-(define-key bibtex-mode-map [menu-bar entry-types bibtex-Book]
-  '("               Book                " . bibtex-Book))
-(define-key bibtex-mode-map [menu-bar entry-types bibtex-Booklet]
-  '("             Booklet               " . bibtex-Booklet))
-(define-key bibtex-mode-map [menu-bar entry-types bibtex-InProceedings]
-  '("            Conference             " . bibtex-InProceedings))
-(define-key bibtex-mode-map [menu-bar entry-types bibtex-MastersThesis]
-  '("         Master's Thesis           " . bibtex-MastersThesis))
-;define-key bibtex-mode-map [menu-bar entry-types bibtex-DEAthesis]
-;'(("            DEA Thesis             " . bibtex-DEAthesis))
-(define-key bibtex-mode-map [menu-bar entry-types bibtex-PhdThesis]
-  '("            Phd. Thesis            " . bibtex-PhdThesis))
-(define-key bibtex-mode-map [menu-bar entry-types bibtex-TechReport]
-  '("         Technical Report          " . bibtex-TechReport))
-(define-key bibtex-mode-map [menu-bar entry-types bibtex-Manual]
-  '("         technical Manual          " . bibtex-Manual))
-(define-key bibtex-mode-map [menu-bar entry-types bibtex-Proceedings]
-  '("      conference Proceedings       " . bibtex-Proceedings))
-(define-key bibtex-mode-map [menu-bar entry-types bibtex-InBook]
-  '("        a chapter in a Book        " . bibtex-InBook))
-(define-key bibtex-mode-map [menu-bar entry-types bibtex-InCollection]
-  '("    an article in a Collection     " . bibtex-InCollection))
-(define-key bibtex-mode-map [menu-bar entry-types bibtex-Misc]
-  '("           miscellaneous           " . bibtex-Misc))
-(define-key bibtex-mode-map [menu-bar entry-types bibtex-Unpublished]
-  '("            unpublished            " . bibtex-Unpublished))
-(define-key bibtex-mode-map [menu-bar entry-types bibtex-string]
-  '("              string               " . bibtex-string))
-(define-key bibtex-mode-map [menu-bar entry-types bibtex-preamble]
-  '("             preamble              " . bibtex-preamble))
-
-(define-key bibtex-mode-map [menu-bar move/edit]
-  (cons "Bibtex Edit" (make-sparse-keymap "Bibtex Edit")))
-
-(define-key bibtex-mode-map [menu-bar move/edit bibtex-next-field]
-  '("            next field             " . bibtex-next-field))
-(define-key bibtex-mode-map [menu-bar move/edit bibtex-find-text]
-  '("          to end of field          " . bibtex-find-text))
-(define-key bibtex-mode-map [menu-bar move/edit bibtex-pop-previous]
-  '("snatch from similar preceding field" . bibtex-pop-previous))
-(define-key bibtex-mode-map [menu-bar move/edit bibtex-pop-next]
-  '("snatch from similar following field" . bibtex-pop-next))
-(define-key bibtex-mode-map [menu-bar move/edit bibtex-remove-OPT]
-  '("            remove OPT             " . bibtex-remove-OPT))
-(define-key bibtex-mode-map [menu-bar move/edit bibtex-remove-double-quotes]
-  '("           remove quotes           " . bibtex-remove-double-quotes))
-(define-key bibtex-mode-map [menu-bar move/edit bibtex-clean-entry]
-  '("          clean up entry           " . bibtex-clean-entry))
-(define-key bibtex-mode-map [menu-bar move/edit find-bibtex-duplicates]
-  '("          find duplicates          " . find-bibtex-duplicates))
-(define-key bibtex-mode-map [menu-bar move/edit sort-bibtex-entries]
-  '("           sort entries            " . sort-bibtex-entries))
-(define-key bibtex-mode-map [menu-bar move/edit validate-bibtex-buffer]
-  '("         validate entries          " . validate-bibtex-buffer))
-
-
-;; Please don't send anything to bug-gnu-emacs about these Sunwindows functions
-;; since we aren't interested.  See etc/SUN-SUPPORT for the reasons why
-;; we consider this nothing but a distraction from our work.
-
-;(defmacro eval-in-menu-window (&rest l)
-;  "Evaluates its argument in the window in which the mouse button was pressed."
-;  (list 'eval-in-window '*menu-window* l))
-
-;(defmenu bibtex-sun-entry-menu 
-;  ("Article In Conf. Proc." eval-in-menu-window bibtex-InProceedings)
-;  ("Article In Journal" eval-in-menu-window bibtex-Article)
-;  ("Book" eval-in-menu-window bibtex-Book)
-;  ("Booklet" eval-in-menu-window bibtex-Booklet)
-;  ("Master's Thesis" eval-in-menu-window bibtex-MastersThesis)
-;  ("PhD. Thesis" eval-in-menu-window bibtex-PhdThesis)
-;  ("Technical Report" eval-in-menu-window bibtex-TechReport)
-;  ("Technical Manual" eval-in-menu-window bibtex-Manual)
-;  ("Conference Proceedings" eval-in-menu-window bibtex-Proceedings)
-;  ("In A Book" eval-in-menu-window bibtex-InBook)
-;  ("In A Collection" eval-in-menu-window bibtex-InCollection)
-;  ("Miscellaneous" eval-in-menu-window bibtex-Misc)
-;  ("Unpublished" eval-in-menu-window bibtex-Unpublished)
-;  ("string" eval-in-menu-window bibtex-string)
-;  ("preamble" eval-in-menu-window bibtex-preamble))
-;
-;(defmenu bibtex-sun-menu
-;  ("BibTeX menu")
-;  ("add entry" . bibtex-sun-entry-menu)
-;  ("next field" eval-in-menu-window bibtex-next-field nil)
-;  ("to end of field" eval-in-menu-window bibtex-find-text nil)
-;  ("snatch similar preceding field" eval-in-menu-window bibtex-pop-previous 1)
-;  ("snatch similar following field" eval-in-menu-window bibtex-pop-next 1)
-;  ("remove OPT" eval-in-menu-window bibtex-remove-OPT)
-;  ("remove quotes" eval-in-menu-window bibtex-remove-double-quotes)
-;  ("clean entry" eval-in-menu-window bibtex-clean-entry)
-;  ("describe BibTeX mode" eval-in-menu-window describe-mode)
-;  ("Main Emacs menu" . emacs-menu))
- 
-;(defun bibtex-sun-menu-eval (window x y)
-;  "Pop-up menu of BibTeX commands."
-;  (sun-menu-evaluate window (1+ x) (1- y) 'bibtex-sun-menu))
-;
-;(defun bibtex-sun-environment ()
-;  "Set up sun menus for BibTeX mode.  Call it as bibtex-mode-hook, or
-;interactively"
-;  (interactive)
-;  (local-set-mouse  '(text right) 'bibtex-sun-menu-eval))
-;
 
 ;;; bibtex.el ends here
+