diff lisp/autoload.el @ 2548:c4c8a36043be

[xemacs-hg @ 2005-02-03 07:11:19 by ben] behavior ws #4: package-suppress, autoload update/sync, add easy-mmode/regexp-opt to core lread.c, lisp.h: Remove undeeded Vload_file_name_internal_the_purecopy, Qload_file_name -- use internal_bind_lisp_object instead of specbind. Add load-suppress-alist. * easy-mmode.el, regexp-opt.el: Move these files into core. Uncomment stuff depending on new custom.el. autoload.el: Removed. Major update. Sync with FSF 21.2. Create the ability to make custom-defines files. update-elc-2.el, update-elc.el: Rewrite to use new autoload API. update-elc.el: Add easy-mmode.
author ben
date Thu, 03 Feb 2005 07:11:28 +0000
parents 588465af3ca1
children 744de5f3f284
line wrap: on
line diff
--- a/lisp/autoload.el	Thu Feb 03 06:14:40 2005 +0000
+++ b/lisp/autoload.el	Thu Feb 03 07:11:28 2005 +0000
@@ -2,9 +2,10 @@
 
 ;; Copyright (C) 1991-1994, 1997, 2003 Free Software Foundation, Inc.
 ;; Copyright (C) 1995 Tinker Systems and INS Engineering Corp.
-;; Copyright (C) 1996, 2000, 2002, 2003 Ben Wing.
+;; Copyright (C) 1996, 2000, 2002, 2003, 2004 Ben Wing.
 
-;; Author: Roland McGrath <roland@gnu.ai.mit.edu>
+;; Original Author: Roland McGrath <roland@gnu.ai.mit.edu>
+;; Heavily Modified: XEmacs Maintainers
 ;; Keywords: maint
 
 ;; This file is part of XEmacs.
@@ -24,13 +25,17 @@
 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 ;; 02111-1307, USA.
 
-;;; Synched up with: Not synched with FSF.
+;;; Synched up with: FSF 21.2 by Ben Wing.
+;;; Note that update-file-autoloads is seriously modified and not really
+;;; syncable.
 
 ;;; Commentary:
 
 ;; This code keeps auto-autoloads.el files up to date.  It interprets
 ;; magic cookies (of the form ";;;###autoload" in Lisp source files
 ;; and "/* ###autoload */" in C source files) in various useful ways.
+;; It is also used to maintain custom-defines.el files, since most of
+;; the logic for computing them is the same as for auto-autoloads.el.
 
 ;; Usage
 ;; =====
@@ -39,8 +44,7 @@
 ;; build process, is
 
 ;; xemacs -no-packages -batch \
-;;        -eval "(setq generated-autoload-file \"PATH\")" \
-;;        -l autoload -f autoload-update-directory-autoloads PREFIX DIRECTORY
+;;        -l autoload -f batch-update-directory-autoloads PREFIX DIRECTORY
 
 ;; which causes XEmacs to update the file named by PATH from the .el
 ;; files in DIRECTORY (but not recursing into subdirectories) and (if
@@ -61,24 +65,13 @@
 ;; of XEmacs).
 
 ;; The probable next step is to fix up the packages to use the
-;; `autoload-update-directory-autoloads' API.  However, for backward
+;; `batch-update-directory-autoloads' API.  However, for backward
 ;; compatibility with XEmacs 21.4 and 21.1, this can't be done quickly.
 
-;; For now the API used in update-elc-2.el:
-
-;; (let* ((dir "DIRECTORY")
-;;        (generated-autoload-file (expand-file-name "auto-autoloads.el" dir))
-;;        (autoload-package-name "PREFIX"))
-;;   (update-autoload-files (list muledir))
-;;   (byte-recompile-file generated-autoload-file 0))
-
-;; is available, but this ugly kludge is deprecated.  It will be removed
-;; in favor of using proper arguments instead of special variables.
-
 ;; For backward compatibility the API used in the packages/XEmacs.rules:
 
 ;; xemacs -vanilla -batch -eval "$(AUTOLOAD_PACKAGE_NAME)" \
-;;        -l autoload -f batch-update-directory $(AUTOLOAD_PATH)
+;;        -l autoload -f batch-update-autoloads $(AUTOLOAD_PATH)
 
 ;; is supported, and the implementation is unchanged.  However,
 ;; revision of the API (in a backward compatible way) and the
@@ -130,6 +123,10 @@
 
 ;;; Code:
 
+;; Need to load easy-mmode because we expand macro calls to easy-mmode
+;; macros in make-autoloads below.
+(require 'easy-mmode)
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Standard file and directory names
 
@@ -144,6 +141,10 @@
 
 ;; Dynamic variables for communication among functions
 
+;; FSF 21.2:
+;; The autoload file is assumed to contain a trailer starting with a FormFeed
+;; character.
+
 (defvar generated-autoload-file
   (expand-file-name autoload-file-name lisp-directory)
   "*File `update-file-autoloads' puts autoloads into.
@@ -154,6 +155,11 @@
 generally the file named by `autoload-file-name' in the directory being
 updated.  XEmacs.rules setq's this variable for package autoloads.")
 
+(defvar generate-autoload-function
+  #'generate-file-autoloads
+  "Function to generate the autoloads for a file and insert at point.
+Called with one argument, the file.")
+
 (define-obsolete-variable-alias 'autoload-package-name
   'autoload-feature-prefix)
 (defvar autoload-feature-prefix nil
@@ -164,6 +170,9 @@
 auto-autoloads file).  Highest priority candidate except for an explicit
 argument to `autoload-make-feature-name' (q.v.).")
 
+(defvar autoload-feature-suffix "-autoloads"
+  "String added to `autoload-feature-prefix' to create the autoload feature name.")
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Magic strings in source files
 
@@ -210,40 +219,69 @@
 (defconst generate-autoload-section-trailer "\n;;;***\n"
   "String which indicates the end of the section of autoloads for a file.")
 
+(defconst generate-autoload-section-continuation ";;;;;; "
+  "String to add on each continuation of the section header form.")
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Parsing the source file text.
-;; Autoloads in C source differ from those in Lisp source.  For historical
-;; reasons, functions handling only Lisp don't have "lisp" in their names;
-;; maybe this should be changed.
+;; Autoloads in C source differ from those in Lisp source.
 
 (defun make-autoload (form file)
-  "Turn a definition generator FORM into an autoload for source file FILE.
-Returns nil if FORM is not a defun, defun*, defmacro, defmacro*,
-define-skeleton, or define-derived-mode."
-  (let ((car (car-safe form)))
-    (if (memq car '(defun defun* define-skeleton defmacro defmacro*
-		     define-derived-mode))
-	(let ((macrop (memq car '(defmacro defmacro*)))
-	      name doc)
-	  (setq form (cdr form)
-		name (car form)
-		;; Ignore the arguments.
-		form (cdr (cond ((eq car 'define-skeleton)
-				 form)
-				((eq car 'define-derived-mode)
-				 (cddr form))
-				(t
-				 (cdr form))))
-		doc (car form))
-	  (if (stringp doc)
-	      (setq form (cdr form))
-	    (setq doc nil))
-	  (list 'autoload (list 'quote name) file doc
-		(or (eq car 'define-skeleton)
-		    (eq car 'define-derived-mode)
-		    (eq (car-safe (car form)) 'interactive))
-		(if macrop (list 'quote 'macro) nil)))
-      nil)))
+  "Turn FORM into an autoload or defvar for source file FILE.
+Returns nil if FORM is not a special autoload form (i.e. a function definition
+or macro definition or a defcustom)."
+  (let ((car (car-safe form)) expand)
+    (cond
+     ;; For complex cases, try again on the macro-expansion.
+     ((and (memq car '(easy-mmode-define-global-mode
+		       easy-mmode-define-minor-mode define-minor-mode))
+	   (setq expand (let ((load-file-name file)) (macroexpand form)))
+	   (eq (car expand) 'progn)
+	   (memq :autoload-end expand))
+      (let ((end (memq :autoload-end expand)))
+	;; Cut-off anything after the :autoload-end marker.
+	(setcdr end nil)
+	(cons 'progn
+	      (mapcar (lambda (form) (make-autoload form file))
+		      (cdr expand)))))
+
+     ;; For special function-like operators, use the `autoload' function.
+     ((memq car '(defun define-skeleton defmacro define-derived-mode
+		   define-generic-mode easy-mmode-define-minor-mode
+		   easy-mmode-define-global-mode
+		   define-minor-mode defun* defmacro*))
+      (let* ((macrop (memq car '(defmacro defmacro*)))
+	     (name (nth 1 form))
+	     (body (nthcdr (get car 'doc-string-elt) form))
+	     (doc (if (stringp (car body)) (pop body))))
+	;; `define-generic-mode' quotes the name, so take care of that
+	(list 'autoload (if (listp name) name (list 'quote name)) file doc
+	      (or (and (memq car '(define-skeleton define-derived-mode
+				    define-generic-mode
+				    easy-mmode-define-global-mode
+				    easy-mmode-define-minor-mode
+				    define-minor-mode)) t)
+		  (eq (car-safe (car body)) 'interactive))
+	      (if macrop (list 'quote 'macro) nil))))
+
+     ;; Convert defcustom to a simpler (and less space-consuming) defvar,
+     ;; but add some extra stuff if it uses :require.
+     ((eq car 'defcustom)
+      (let ((varname (car-safe (cdr-safe form)))
+	    (init (car-safe (cdr-safe (cdr-safe form))))
+	    (doc (car-safe (cdr-safe (cdr-safe (cdr-safe form)))))
+	    (rest (cdr-safe (cdr-safe (cdr-safe (cdr-safe form))))))
+	(if (not (plist-get rest :require))
+	    `(defvar ,varname ,init ,doc)
+	  `(progn
+	     (defvar ,varname ,init ,doc)
+	     (custom-add-to-group ,(plist-get rest :group)
+				  ',varname 'custom-variable)
+	     (custom-add-load ',varname
+			      ,(plist-get rest :require))))))
+
+     ;; nil here indicates that this is not a special autoload form.
+     (t nil))))
 
 (defun make-c-autoload (module)
   "Make an autoload list for the DEFUN at point in MODULE.
@@ -283,7 +321,7 @@
 ;; Generating autoloads for a single file
 
 ;;;###autoload
-(defun generate-file-autoloads (file &optional funlist)
+(defun generate-file-autoloads (file)
   "Insert at point an autoload section for FILE.
 autoloads are generated for defuns and defmacros in FILE
 marked by `generate-autoload-cookie' (which see).
@@ -291,26 +329,26 @@
 are used."
   (interactive "fGenerate autoloads for file: ")
   (cond ((string-match "\\.el$" file)
-	 (generate-autoload-ish-1
+	 (generate-autoload-type-section
 	  file
 	  (replace-in-string (file-name-nondirectory file) "\\.elc?$" "")
-	  nil #'generate-file-autoloads-1
-	  funlist))
+	  nil #'generate-lisp-file-autoloads-1))
 	;; #### jj, are C++ modules possible?
 	((string-match "\\.c$" file)
-	 (generate-autoload-ish-1
+	 (generate-autoload-type-section
 	  file
 	  (replace-in-string (file-name-nondirectory file) "\\.c$" "")
-	  t #'generate-c-file-autoloads-1
-	  funlist))
+	  t #'generate-c-file-autoloads-1))
 	(t
 	 (error 'wrong-type-argument file "not a C or Elisp source file"))))
 
-(defun* generate-autoload-ish-1 (file load-name literal fun-to-call &rest args)
+(defun* generate-autoload-type-section (file load-name literal fun-to-call)
   "Insert at point an autoload-type section for FILE.
-If LITERAL, open the file literally, without decoding.
-Calls FUN-TO-CALL to compute the autoloads, passing it OUTBUF, LOAD-NAME,
-  TRIM-NAME, and ARGS."
+LOAD-NAME is the non-directory portion of the name, with the final .el, .elc
+or .c section removed.  If LITERAL, open the file literally, without decoding.
+Calls FUN-TO-CALL to compute the autoloads, with the loaded file in the
+current buffer, passing it OUTBUF (where to write the autoloads), LOAD-NAME,
+and TRIM-NAME (result of calling `autoload-trim-file-name' on FILE)."
   (let ((outbuf (current-buffer))
 	(trim-name (autoload-trim-file-name file))
 	(autoloads-done '())
@@ -318,6 +356,7 @@
 	(print-readably t) ; XEmacs
 	(float-output-format nil)
 	(visited (get-file-buffer file))
+	suppress-form
 	;; (done-any nil)
 	output-end)
 
@@ -329,21 +368,74 @@
     ;; subdirectory of the current buffer's directory, we'll make it
     ;; relative to the current buffer's directory.
     (setq file (expand-file-name file))
+    ;; #### FSF 21.2.  Do we want this?
+;     (let* ((source-truename (file-truename file))
+; 	   (dir-truename (file-name-as-directory
+; 			  (file-truename default-directory)))
+; 	   (len (length dir-truename)))
+;       (if (and (< len (length source-truename))
+; 	       (string= dir-truename (substring source-truename 0 len)))
+; 	  (setq file (substring source-truename len))))
+
+    ;; Check for suppression form (XEmacs)
+    (let* ((dir (file-name-directory file))
+	   (_pkg (expand-file-name "_pkg.el" dir))
+	   (pkg-vis (get-file-buffer _pkg))
+	   pkg-buf)
+      (save-excursion
+	(when (file-readable-p _pkg)
+	  (unwind-protect
+	      (progn
+		(let ((find-file-hooks nil)
+		      (enable-local-variables nil))
+		  (set-buffer (or pkg-vis (find-file-noselect _pkg)))
+		  (set-syntax-table emacs-lisp-mode-syntax-table))
+		(save-excursion
+		  (save-restriction
+		    (widen)
+		    (goto-char (point-min))
+		    (block nil
+		      (while (search-forward "(package-suppress" nil t)
+			;; skip over package-name
+			(forward-sexp 1)
+			(let ((supfile (read (current-buffer))))
+			  (when (equal supfile load-name)
+			    (setq suppress-form (eval (read (current-buffer))))
+			    (return))))))))
+	    (unless pkg-vis
+	      ;; We created this buffer, so we should kill it.
+	      (if pkg-buf (kill-buffer pkg-buf)))))))
 
     (save-excursion
       (unwind-protect
 	  (progn
-	    (let ((find-file-hooks nil)
-		  (enable-local-variables nil))
+	    (let (;(find-file-hooks nil)
+		  ;(enable-local-variables nil)
+		  )
 	      (set-buffer (or visited (find-file-noselect file literal literal
 							  )))
 	      ;; This doesn't look right for C files, but it is.  The only
 	      ;; place we need the syntax table is when snarfing the Lisp
 	      ;; function name.
 	      (set-syntax-table emacs-lisp-mode-syntax-table))
+; 	    (if visited
+; 		(set-buffer visited)
+; 	      ;; It is faster to avoid visiting the file.
+; 	      (set-buffer (get-buffer-create " *generate-autoload-file*"))
+; 	      (kill-all-local-variables)
+; 	      (erase-buffer)
+; 	      (setq buffer-undo-list t
+; 		    buffer-read-only nil)
+; 	      ;; This doesn't look right for C files, but it is.  The only
+; 	      ;; place we need the syntax table is when snarfing the Lisp
+; 	      ;; function name.
+; 	      (emacs-lisp-mode)
+; 	      (if literal
+; 		  (insert-file-contents-literally file nil)
+; 		(insert-file-contents file nil)))
 	    (unless (setq autoloads-done
-			  (apply fun-to-call outbuf load-name trim-name args))
-	      (return-from generate-autoload-ish-1))
+			  (funcall fun-to-call outbuf load-name trim-name))
+	      (return-from generate-autoload-type-section))
 	    )
 	(unless visited
 	  ;; We created this buffer, so we should kill it.
@@ -354,108 +446,124 @@
 	;; XEmacs -- always do this so that we cache the information
 	;; that we've processed the file already.
 	(progn
+	  ;; Insert the section-header line
+	  ;; which lists the file name and which functions are in it, etc.
 	  (insert generate-autoload-section-header)
-	  (prin1 (list 'autoloads autoloads-done load-name trim-name)
+	  (prin1 (list 'autoloads autoloads-done load-name trim-name
+		       ;; In FSF 21.2.  Also in FSF 19.30.  Presumably
+		       ;; deleted from XEmacs.
+		       ;; (nth 5 (file-attributes file))
+		       )
 		 outbuf)
 	  (terpri outbuf)
-	  ;;;; (insert ";;; Generated autoloads from "
-	  ;;;;	  (autoload-trim-file-name file) "\n")
-	  ;; Warn if we put a line in auto-autoloads.el
-	  ;; that is long enough to cause trouble.
-	  (when (< output-end (point))
-	    (setq output-end (point-marker)))
-	  (while (< (point) output-end)
-	    ;; (let ((beg (point)))
-	      (end-of-line)
-	      ;; Emacs -- I still haven't figured this one out.
-	      ;; (if (> (- (point) beg) 900)
-		  ;; (progn
-		    ;; (message "A line is too long--over 900 characters")
-		    ;; (sleep-for 2)
-		    ;; (goto-char output-end)))
-	      ;; )
-	    (forward-line 1))
+	  ;; #### Alas, we will have to think about this.  Adding this means
+	  ;; that, once we have created or maintained an auto-autoloads file,
+	  ;; we alone and our successors can update the file.  The file itself
+	  ;; will work fine in older XEmacsen, but they won't be able to
+	  ;; update autoloads -- hence, to build.
+; 	  ;; Break that line at spaces, to avoid very long lines.
+; 	  ;; Make each sub-line into a comment.
+; 	  (with-current-buffer outbuf
+; 	    (save-excursion
+; 	      (forward-line -1)
+; 	      (while (not (eolp))
+; 		(move-to-column 64)
+; 		(skip-chars-forward "^ \n")
+; 		(or (eolp)
+; 		    (insert "\n" generate-autoload-section-continuation)))))
+	  ;; XEmacs: This was commented out before.  #### Correct?
+; 	  (insert ";;; Generated autoloads from "
+; 		  (autoload-trim-file-name file) "\n")
+	  ;; XEmacs -- handle suppression
+	  (when suppress-form
+	    (insert "\n;;; Suppress form from _pkg.el\n")
+	    (insert "(unless " (prin1-to-string suppress-form) "\n\n"))
 	  (goto-char output-end)
+	  ;; XEmacs -- handle suppression
+	  (when suppress-form
+	    (insert "\n) ;; unless (suppressed)\n"))
 	  (insert generate-autoload-section-trailer)))
-    (or noninteractive ; XEmacs: only need one line in -batch mode.
-	(message "Generating autoloads for %s...done" file))))
+    ))
+
 
-(defun* generate-file-autoloads-1 (outbuf load-name trim-name funlist)
-  "Insert at point an autoload section for FILE.
-autoloads are generated for defuns and defmacros in FILE
-marked by `generate-autoload-cookie' (which see).
-If FILE is being visited in a buffer, the contents of the buffer
-are used."
+(defun process-one-lisp-autoload (autoloads-done outbuf load-name)
+  "Process a single autoload at point and write to OUTBUF.
+Point should be just after a magic cookie string (e.g. ;;;###autoload).
+Updates AUTOLOADS-DONE and returns the new value."
+  (skip-chars-forward " \t")
+  ;; (setq done-any t)
+  (if (eolp)
+      ;; Read the next form and make an autoload.
+      (let* ((form (prog1 (read (current-buffer))
+		     (or (bolp) (forward-line 1))))
+	     (autoload (make-autoload form load-name)))
+	(if autoload
+	    (setq autoloads-done (cons (nth 1 form)
+				       autoloads-done))
+	  (setq autoload form))
+	(autoload-print-form autoload outbuf ""))
+    ;; Copy the rest of the line to the output.
+    (cond ((looking-at "immediate\\s *$") ; XEmacs
+	   ;; This is here so that you can automatically
+	   ;; have small hook functions copied to
+	   ;; auto-autoloads.el so that it's not necessary
+	   ;; to load a whole file just to get a two-line
+	   ;; do-nothing find-file-hook... --Stig
+	   (forward-line 1)
+	   (let ((begin (point)))
+	     (forward-sexp)
+	     (forward-line 1)
+	     (princ (buffer-substring begin (point)) outbuf)))
+	  (t
+	   (princ (buffer-substring
+		   (progn
+		     ;; Back up over whitespace, to preserve it.
+		     (skip-chars-backward " \f\t")
+		     (if (= (char-after (1+ (point))) ? )
+			 ;; Eat one space.
+			 (forward-char 1))
+		     (point))
+		   (progn (forward-line 1) (point)))
+		  outbuf))))
+  autoloads-done)
+
+(defun* generate-lisp-file-autoloads-1 (outbuf load-name trim-name)
+  "Insert at point in OUTBUF an autoload section for an Elisp file.
+The file is assumed to be already loaded and in the current buffer.
+autoloads are generated for defuns and defmacros marked by
+`generate-autoload-cookie' (which see)."
   (let ((autoloads-done '())
-	(dofiles (not (null funlist)))
 	)
-
     (save-excursion
       (save-restriction
 	(widen)
 	(goto-char (point-min))
 	(unless (search-forward generate-autoload-cookie nil t)
 	  (message "No autoloads found in %s" trim-name)
-	  (return-from generate-file-autoloads-1 nil))
+	  (return-from generate-lisp-file-autoloads-1 nil))
 
 	(message "Generating autoloads for %s..." trim-name)
 	(goto-char (point-min))
-	(while (if dofiles funlist (not (eobp)))
-	  (if (not dofiles)
-	      (skip-chars-forward " \t\n\f")
-	    (goto-char (point-min))
-	    (re-search-forward
-	     (concat "(def\\(un\\|var\\|const\\|macro\\) "
-		     (regexp-quote (symbol-name (car funlist)))
-		     "\\s "))
-	    (goto-char (match-beginning 0)))
+	(while (not (eobp))
+	  (skip-chars-forward " \t\n\f")
 	  (cond
-	   ((or dofiles
-		(looking-at (regexp-quote generate-autoload-cookie)))
-	    (if dofiles
-		nil
-	      (search-forward generate-autoload-cookie)
-	      (skip-chars-forward " \t"))
-	    ;; (setq done-any t)
-	    (if (or dofiles (eolp))
-		;; Read the next form and make an autoload.
-		(let* ((form (prog1 (read (current-buffer))
-			       (or (bolp) (forward-line 1))))
-		       (autoload (make-autoload form load-name))
-		       (doc-string-elt (get (car-safe form)
-					    'doc-string-elt)))
-		  (if autoload
-		      (setq autoloads-done (cons (nth 1 form)
-						 autoloads-done))
-		    (setq autoload form))
-		  (print-autoload autoload doc-string-elt outbuf ""))
-	      ;; Copy the rest of the line to the output.
-	      (let ((begin (point)))
-		;; (terpri outbuf)
-		(cond ((looking-at "immediate\\s *$") ; XEmacs
-		       ;; This is here so that you can automatically
-		       ;; have small hook functions copied to
-		       ;; auto-autoloads.el so that it's not necessary
-		       ;; to load a whole file just to get a two-line
-		       ;; do-nothing find-file-hook... --Stig
-		       (forward-line 1)
-		       (setq begin (point))
-		       (forward-sexp)
-		       (forward-line 1))
-		      (t
-		       (forward-line 1)))
-		(princ (buffer-substring begin (point)) outbuf))))
+	   ((looking-at (regexp-quote generate-autoload-cookie))
+	    (search-forward generate-autoload-cookie)
+	    (setq autoloads-done
+		  (process-one-lisp-autoload autoloads-done outbuf load-name)))
 	   ((looking-at ";")
 	    ;; Don't read the comment.
 	    (forward-line 1))
 	   (t
 	    (forward-sexp 1)
 	    (forward-line 1)))
-	  (if dofiles
-	      (setq funlist (cdr funlist))))))
+	  )))
+    (or noninteractive ; XEmacs: only need one line in -batch mode.
+	(message "Generating autoloads for %s...done" trim-name))
     autoloads-done))
 
-(defun* generate-c-file-autoloads-1 (outbuf load-name trim-name funlist)
+(defun* generate-c-file-autoloads-1 (outbuf load-name trim-name
+				     &optional funlist)
   "Insert at point an autoload section for the C file FILE.
 autoloads are generated for defuns and defmacros in FILE
 marked by `generate-c-autoload-cookie' (which see).
@@ -488,7 +596,7 @@
 		(let ((autoload (make-c-autoload load-name)))
 		  (when autoload
 		    (push (nth 1 (nth 1 autoload)) autoloads-done)
-		    (print-autoload autoload 3 outbuf "  "))))
+		    (autoload-print-form autoload outbuf "  "))))
 	      ;; close the princ'd `when' form
 	      (princ ")" outbuf))
 	  (goto-char (point-min))
@@ -505,91 +613,175 @@
 	      (let ((autoload (make-c-autoload load-name)))
 		(when autoload
 		  (push (nth 1 (nth 1 autoload)) autoloads-done)
-		  (print-autoload autoload 3 outbuf "  ")))
+		  (autoload-print-form autoload outbuf "  ")))
 	      (setq match
 		    (search-forward generate-c-autoload-cookie nil t)))
 	    ;; close the princ'd `when' form
 	    (princ ")" outbuf)))))
+    (or noninteractive ; XEmacs: only need one line in -batch mode.
+	(message "Generating autoloads for %s...done" trim-name))
     autoloads-done))
 
-;; Assorted utilities for generating  autoloads and pieces thereof
+;;;###autoload
+(defun generate-custom-defines (file)
+  "Insert at point a custom-define section for FILE.
+If FILE is being visited in a buffer, the contents of the buffer
+are used."
+  (interactive "fGenerate custom defines for file: ")
+  (cond ((string-match "\\.el$" file)
+	 (generate-autoload-type-section
+	  file
+	  (replace-in-string (file-name-nondirectory file) "\\.elc?$" "")
+	  nil #'generate-custom-defines-1))
+	((string-match "\\.c$" file)
+	 ;; no way to generate custom-defines for C files (currently?),
+	 ;; but cannot signal an error.
+	 nil)
+	(t
+	 (error 'wrong-type-argument file "not a C or Elisp source file"))))
 
-(defun print-autoload (autoload doc-string-elt outbuf margin)
+(defun* generate-custom-defines-1 (outbuf load-name trim-name)
+  "Insert at point in OUTBUF a custom-define section for an Elisp file.
+This contains all defcustoms and defgroups in the file.
+The file is assumed to be already loaded and in the current buffer."
+  (let* ((search-regexp-1 "^(\\(defcustom\\|defgroup\\) ")
+	 (search-string-2 ";;;###custom-define")
+	 (search-regexp-2 (regexp-quote search-string-2))
+	 (autoloads-done '()))
+    (save-excursion
+      (save-restriction
+	(widen)
+	(goto-char (point-min))
+	(unless (or (re-search-forward search-regexp-1 nil t)
+		    (re-search-forward search-regexp-2 nil t))
+	  (message "No custom defines found in %s" trim-name)
+	  (return-from generate-custom-defines-1 nil))
+	(message "Generating custom defines for %s..." trim-name)
+	(princ "(defconst custom-define-current-source-file " outbuf)
+	(prin1 (file-relative-name (buffer-file-name)
+				   (symbol-value-in-buffer 'default-directory
+							   outbuf)) outbuf)
+	(princ ")\n" outbuf)
+	       
+	(goto-char (point-min))
+	(while (not (eobp))
+	  (skip-chars-forward " \t\n\f")
+	  (cond
+	   ((looking-at search-regexp-1)
+	    ;; Read the next form and copy it to make an autoload.
+	    (let* ((form (prog1 (read (current-buffer))
+			   (or (bolp) (forward-line 1))))
+		   (autoload form ;(make-autoload form load-name)
+		     ))
+	      (if autoload
+		  (setq autoloads-done (cons (nth 1 form)
+					     autoloads-done))
+		(setq autoload form))
+	      (autoload-print-form autoload outbuf ""))
+	    )
+	   ((looking-at search-regexp-2)
+	    (search-forward search-string-2)
+	    (beep)
+	    (setq autoloads-done
+		  (process-one-lisp-autoload autoloads-done outbuf load-name)))
+	   ((looking-at ";")
+	    ;; Don't read the comment.
+	    (forward-line 1))
+	   (t
+	    (forward-sexp 1)
+	    (forward-line 1)))
+	  )))
+    (or noninteractive ; XEmacs: only need one line in -batch mode.
+	(message "Generating custom defines for %s...done" trim-name))
+    autoloads-done))
+
+;; Assorted utilities for generating autoloads and pieces thereof
+
+(defun autoload-print-form (form outbuf margin)
   "Print an autoload form, handling special characters.
 In particular, print docstrings with escapes inserted before left parentheses
 at the beginning of lines and ^L characters."
-  (if (and doc-string-elt (stringp (nth doc-string-elt autoload)))
-      ;; We need to hack the printing because the doc-string must be
-      ;; printed specially for make-docfile (sigh).
-      (let* ((p (nthcdr (1- doc-string-elt) autoload))
-	     (elt (cdr p))
-	     (start-string (format "\n%s(" margin)))
-	(setcdr p nil)
-	(princ start-string outbuf)
-	;; XEmacs change: don't let ^^L's get into
-	;; the file or sorting is hard.
-	(let ((print-escape-newlines t)
-	      (p (save-excursion
-		   (set-buffer outbuf)
-		   (point)))
+  (cond
+   ;; If the form is a sequence, recurse.
+   ((eq (car form) 'progn)
+    (mapcar #'(lambda (x) (autoload-print-form x outbuf margin))
+	    (cdr form)))
+   ;; Symbols at the toplevel are meaningless.
+   ((symbolp form) nil)
+   (t
+    (let ((doc-string-elt (get (car-safe form) 'doc-string-elt)))
+      (if (and doc-string-elt (stringp (nth doc-string-elt form)))
+	  ;; We need to hack the printing because the doc-string must be
+	  ;; printed specially for make-docfile (sigh).
+	  (let* ((p (nthcdr (1- doc-string-elt) form))
+		 (elt (cdr p))
+		 (start-string (format "\n%s(" margin)))
+	    (setcdr p nil)
+	    (princ start-string outbuf)
+	    ;; XEmacs change: don't let ^^L's get into
+	    ;; the file or sorting is hard.
+	    (let ((print-escape-newlines t)
+		  ;;#### FSF 21.2 (print-escape-nonascii t)
+		  (p (point outbuf))
+		  p2)
+	      (mapcar #'(lambda (elt)
+			  (prin1 elt outbuf)
+			  (princ " " outbuf))
+		      form)
+	      (with-current-buffer outbuf
+		(setq p2 (point-marker))
+		(goto-char p)
+		(save-match-data
+		  (while (search-forward "\^L" p2 t)
+		    (delete-char -1)
+		    (insert "\\^L")))
+		(goto-char p2)))
+	    (princ "\"\\\n" outbuf)
+	    (let ((begin (point outbuf)))
+	      (princ (substring (prin1-to-string (car elt)) 1) outbuf)
+	      ;; Insert a backslash before each ( that appears at the beginning
+	      ;; of a line in the doc string.
+	      (with-current-buffer outbuf
+		(save-excursion
+		  (while (search-backward start-string begin t)
+		    (forward-char 1)
+		    (insert "\\"))))
+	      (if (null (cdr elt))
+		  (princ ")" outbuf)
+		(princ " " outbuf)
+		(princ (substring (prin1-to-string (cdr elt)) 1) outbuf))
+	      (terpri outbuf)
+	      (princ margin outbuf)))
+	;; XEmacs change: another ^L hack
+	(let ((p (point outbuf))
+	      (print-escape-newlines t)
+	      ;;#### FSF 21.2 (print-escape-nonascii t)
 	      p2)
-	  (mapcar #'(lambda (elt)
-		      (prin1 elt outbuf)
-		      (princ " " outbuf))
-		  autoload)
-	  (save-excursion
-	    (set-buffer outbuf)
+	  (print form outbuf)
+	  (with-current-buffer outbuf
 	    (setq p2 (point-marker))
 	    (goto-char p)
 	    (save-match-data
 	      (while (search-forward "\^L" p2 t)
 		(delete-char -1)
 		(insert "\\^L")))
-	    (goto-char p2)))
-	(princ "\"\\\n" outbuf)
-	(let ((begin (save-excursion
-		       (set-buffer outbuf)
-		       (point))))
-	  (princ (substring (prin1-to-string (car elt)) 1) outbuf)
-	  ;; Insert a backslash before each ( that appears at the beginning
-	  ;; of a line in the doc string.
-	  (save-excursion
-	    (set-buffer outbuf)
-	    (save-excursion
-	      (while (search-backward start-string begin t)
-		(forward-char 1)
-		(insert "\\"))))
-	  (if (null (cdr elt))
-	      (princ ")" outbuf)
-	    (princ " " outbuf)
-	    (princ (substring (prin1-to-string (cdr elt)) 1) outbuf))
-	  (terpri outbuf)
-	  (princ margin outbuf)))
-    ;; XEmacs change: another ^L hack
-    (let ((p (save-excursion
-	       (set-buffer outbuf)
-	       (point)))
-	  (print-escape-newlines t)
-	  p2)
-      (print autoload outbuf)
-      (save-excursion
-	(set-buffer outbuf)
-	(setq p2 (point-marker))
-	(goto-char p)
-	(save-match-data
-	  (while (search-forward "\^L" p2 t)
-	    (delete-char -1)
-	    (insert "\\^L")))
-	(goto-char p2)))))
+	    (goto-char p2))))))))
 
 ;;; Forms which have doc-strings which should be printed specially.
 ;;; A doc-string-elt property of ELT says that (nth ELT FORM) is
 ;;; the doc-string in FORM.
 ;;;
-;;; defvar and defconst should be also be marked in this way.  There is
-;;; no interference from make-docfile, which only processes those files
-;;; that are loaded into the dumped Emacs, and those files should
-;;; never have anything autoloaded here.  Problems only occur with files
+;;; There used to be the following note here:
+;;; ;;; Note: defconst and defvar should NOT be marked in this way.
+;;; ;;; We don't want to produce defconsts and defvars that
+;;; ;;; make-docfile can grok, because then it would grok them twice,
+;;; ;;; once in foo.el (where they are given with ;;;###autoload) and
+;;; ;;; once in loaddefs.el.
+;;;
+;;; Counter-note: Yes, they should be marked in this way.
+;;; make-docfile only processes those files that are loaded into the
+;;; dumped Emacs, and those files should never have anything
+;;; autoloaded here.  The above-feared problem only occurs with files
 ;;; which have autoloaded entries *and* are processed by make-docfile;
 ;;; there should be no such files.
 
@@ -597,11 +789,18 @@
 (put 'defun    'doc-string-elt 3)
 (put 'defun*   'doc-string-elt 3)
 (put 'defvar   'doc-string-elt 3)
+(put 'defcustom 'doc-string-elt 3)
 (put 'defconst 'doc-string-elt 3)
 (put 'defmacro 'doc-string-elt 3)
 (put 'defmacro* 'doc-string-elt 3)
-(put 'define-skeleton 'doc-string-elt 3)
+(put 'defsubst 'doc-string-elt 3)
+(put 'define-skeleton 'doc-string-elt 2)
 (put 'define-derived-mode 'doc-string-elt 4)
+(put 'easy-mmode-define-minor-mode 'doc-string-elt 2)
+(put 'define-minor-mode 'doc-string-elt 2)
+(put 'define-generic-mode 'doc-string-elt 7)
+;; defin-global-mode has no explicit docstring.
+(put 'easy-mmode-define-global-mode 'doc-string-elt 1000)
 
 (defun autoload-trim-file-name (file)
   "Returns relative pathname of FILE including the last directory.
@@ -615,6 +814,27 @@
    ;; #### is this a good idea?
    "\\\\" "/"))
 
+(defun autoload-read-section-header ()
+  "Read a section header form.
+Since continuation lines have been marked as comments,
+we must copy the text of the form and remove those comment
+markers before we call `read'."
+  (save-match-data
+    (let ((beginning (point))
+	  string)
+      (forward-line 1)
+      (while (looking-at generate-autoload-section-continuation)
+	(forward-line 1))
+      (setq string (buffer-substring beginning (point)))
+      (with-current-buffer (get-buffer-create " *autoload*")
+	(erase-buffer)
+	(insert string)
+	(goto-char (point-min))
+	(while (search-forward generate-autoload-section-continuation nil t)
+	  (replace-match " "))
+	(goto-char (point-min))
+	(read (current-buffer))))))
+
 ;;;###autoload
 (defun update-file-autoloads (file)
   "Update the autoloads for FILE in `generated-autoload-file'
@@ -633,16 +853,42 @@
 	  (trim-name (autoload-trim-file-name file))
 	  section-begin form)
       (save-excursion
+	;; FSF has: [[ We want to get a value for generated-autoload-file
+	;; from the local variables section if it's there. ]] Not
+	;; applicable in XEmacs, since we always keep the autoloads
+	;; up-to-date.
+
+	;; #### FSF 21.2 adds: [[ We must read/write the file without any
+	;; code conversion, but still decode EOLs. ]] Not clear if we need
+	;; this. --ben
+	;; (let ((coding-system-for-read 'raw-text))
 	(let ((find-file-hooks nil))
 	  (set-buffer (or (get-file-buffer generated-autoload-file)
 			  (find-file-noselect generated-autoload-file))))
+	;; FSF 21.2 says:
+
+	;; [[ This is to make generated-autoload-file have Unix EOLs, so
+	;; that it is portable to all platforms. ]]
+	;; (setq buffer-file-coding-system 'raw-text-unix))
+	;; Not applicable in XEmacs, since we always keep the autoloads
+	;; up-to-date and recompile when we build.
+
+	;; FSF 21.2: [not applicable to XEmacs]
+; 	(or (> (buffer-size) 0)
+; 	    (error "Autoloads file %s does not exist" buffer-file-name))
+; 	(or (file-writable-p buffer-file-name)
+; 	    (error "Autoloads file %s is not writable" buffer-file-name))
+
+	;; NOTE: The rest of this function is totally changed from FSF.
+	;; Hence, not synched.
+
 	;; Make sure we can scribble in it.
 	(setq buffer-read-only nil)
 	;; First delete all sections for this file.
 	(goto-char (point-min))
 	(while (search-forward generate-autoload-section-header nil t)
 	  (setq section-begin (match-beginning 0))
-	  (setq form (read (current-buffer)))
+	  (setq form (autoload-read-section-header))
 	  (when (string= (nth 2 form) load-name)
 	    (search-forward generate-autoload-section-trailer)
 	    (delete-region section-begin (point))))
@@ -651,7 +897,7 @@
 	(block find-insertion-point
 	  (goto-char (point-min))
 	  (while (search-forward generate-autoload-section-header nil t)
-	    (setq form (read (current-buffer)))
+	    (setq form (autoload-read-section-header))
 	    (when (string< trim-name (nth 3 form))
 	      ;; Found alphabetically correct insertion point
 	      (goto-char (match-beginning 0))
@@ -661,65 +907,15 @@
 	    (goto-char (point-max))))	; Append.
 
 	;; Add in new sections for file
-	(generate-file-autoloads file))
+	(funcall generate-autoload-function file))
 
       (when (interactive-p) (save-buffer)))))
 
-;;;###autoload
-(defun update-autoloads-here ()
-  "Update sections of the current buffer generated by `update-file-autoloads'."
-  (interactive)
-  (let ((generated-autoload-file (buffer-file-name)))
-    (save-excursion
-      (goto-char (point-min))
-      (while (search-forward generate-autoload-section-header nil t)
-	(let* ((form (condition-case ()
-			 (read (current-buffer))
-		       (end-of-file nil)))
-	       (file (nth 3 form)))
-	  ;; XEmacs change: if we can't find the file as specified, look
-	  ;; around a bit more.
-	  (cond ((and (stringp file)
-		      (or (get-file-buffer file)
-			  (file-exists-p file))))
-		((and (stringp file)
-		      (save-match-data
-			(let ((loc (locate-file (file-name-nondirectory file)
-						load-path)))
-			  (if (null loc)
-			      nil
-			    (setq loc (expand-file-name
-				       (autoload-trim-file-name loc)
-				       ".."))
-			    (if (or (get-file-buffer loc)
-				    (file-exists-p loc))
-				(setq file loc)
-			      nil))))))
-		(t
-		 (setq file
-		       (if (y-or-n-p
-			    (format
-			     "Can't find library `%s'; remove its autoloads? "
-			     (nth 2 form) file))
-			   t
-			 (condition-case ()
-			     (read-file-name
-			      (format "Find `%s' load file: "
-				      (nth 2 form))
-			      nil nil t)
-			   (quit nil))))))
-	  (if file
-	      (let ((begin (match-beginning 0)))
-		(search-forward generate-autoload-section-trailer)
-		(delete-region begin (point))))
-	  (if (stringp file)
-	      (generate-file-autoloads file)))))))
-
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Utilities for batch updates
 
 ;;;###autoload
-(defun autoload-update-directory-autoloads ()
+(defun batch-update-directory-autoloads ()
   "Update the autoloads for a directory, using a specified feature prefix.
 Must be used only with -batch.  The feature prefix and directory to update
 are taken from the first and second elements of `command-line-args-left',
@@ -731,15 +927,32 @@
 
 #### The API and semantics of this function are subject to change."
   (unless noninteractive
-    (error "autoload-batch-update-autoloads: may be used only with -batch"))
-  (let* ((autoload-feature-prefix (car command-line-args-left))
-	 (dir (cadr command-line-args-left))
-	 (generated-autoload-file (expand-file-name autoload-file-name dir)))
-    (update-autoload-files (list dir) t t)
-    (setq command-line-args-left (cddr command-line-args-left))))
+    (error "batch-update-directory-autoloads: may be used only with -batch"))
+  (update-autoload-files (list (cadr command-line-args-left))
+			 (car command-line-args-left) nil t)
+  (setq command-line-args-left (cddr command-line-args-left)))
 
 ;;;###autoload
-(defun update-autoload-files (files-or-dirs &optional all-into-one-file force)
+(defun batch-update-directory-custom-defines ()
+  "Update the custom defines for a directory, using a specified feature prefix.
+Must be used only with -batch.  The feature prefix and directory to update
+are taken from the first and second elements of `command-line-args-left',
+respectively, and they are then removed from `command-line-args-left'.
+
+Runs `update-file-autoloads' on each file in the given directory.  Always
+rewrites the autoloads file, even if unchanged.  Makes a feature name by
+applying `autoload-make-feature-name' to the specified feature prefix.
+
+#### The API and semantics of this function are subject to change."
+  (unless noninteractive
+    (error "batch-update-directory-custom-defines: may be used only with -batch"))
+  (update-custom-define-files (list (cadr command-line-args-left))
+			      (car command-line-args-left) nil t)
+  (setq command-line-args-left (cddr command-line-args-left)))
+
+;;;###autoload
+(defun update-autoload-files (files-or-dirs feature-prefix
+			      &optional into-file force)
   "Update all the autoload files associated with FILES-OR-DIRS.
 FILES-OR-DIRS is a list of files and/or directories to be processed.
 
@@ -747,98 +960,144 @@
 each element of FILES-OR-DIRS.  Fixup code testing for the autoload file's
 feature and to provide the feature is added.
 
-If optional ALL-INTO-ONE-FILE is non-`nil', `generated-autoload-file'
-should be set to the name of an autoload file and all autoloads will be
-placed in that file.  `autoload-feature-prefix' should be set to an
-appropriate prefix which will be concatenated with \"-autoloads\" to
-produce the feature name.  Otherwise the appropriate autoload file for
-each file or directory (located in that directory, or in the directory of
-the specified file) will be updated with the directory's or file's
-autoloads and the protective forms will be added, and the files will be
-saved.  Use of the default here is unreliable, and therefore deprecated.
+If optional INTO-FILE is non-`nil', it should specify a file into which
+the autoloads will be placed.  Otherwise, the autoloads will be placed into
+a file named `auto-autoloads.el' in the directory of each element in
+FILES-OR-DIRS.
+
+FEATURE-PREFIX should be set to an appropriate prefix which will
+be concatenated with \"-autoloads\" to produce the feature name.  Otherwise
+the appropriate autoload file for each file or directory (located in that
+directory, or in the directory of the specified file) will be updated with
+the directory's or file's autoloads and the protective forms will be added,
+and the files will be saved.  Use of the default here is unreliable, and
+therefore deprecated.
 
 Note that if some of FILES-OR-DIRS are directories, recursion goes only
 one level deep.
 
 If FORCE is non-nil, always save out the autoload files even if unchanged."
+  (or (listp files-or-dirs) (setq files-or-dirs (list files-or-dirs)))
   (let ((defdir (directory-file-name default-directory))
 	;; value for all-into-one-file
-	(autoload-feature-name (autoload-make-feature-name))
-	(enable-local-eval nil))	; Don't query in batch mode.
+	(autoload-feature-name (autoload-make-feature-name feature-prefix))
+	(enable-local-eval nil)	; Don't query in batch mode.
+	(autoload-feature-prefix feature-prefix)
+	;; protect from change
+	(generated-autoload-file generated-autoload-file))
     (dolist (arg files-or-dirs)
       (setq arg (expand-file-name arg defdir))
       (cond
        ((file-directory-p arg)
+	(setq generated-autoload-file
+	      (or into-file (expand-file-name autoload-file-name arg)))
 	(message "Updating autoloads for directory %s..." arg)
-	(update-autoloads-from-directory arg))
+	(let ((simple-dir (file-name-as-directory
+			   (file-name-nondirectory
+			    (directory-file-name arg))))
+	      (enable-local-eval nil))
+	  (save-excursion
+	    (let ((find-file-hooks nil))
+	      (set-buffer (find-file-noselect generated-autoload-file)))
+	    (goto-char (point-min))
+	    (while (search-forward generate-autoload-section-header nil t)
+	      (let* ((begin (match-beginning 0))
+		     (form (autoload-read-section-header))
+		     (file (nth 3 form)))
+		(when (and (stringp file)
+			   (string= (file-name-directory file) simple-dir)
+			   (not (file-exists-p
+				 (expand-file-name
+				  (file-name-nondirectory file) arg))))
+		  ;; Remove the obsolete section.
+		  (search-forward generate-autoload-section-trailer)
+		  (delete-region begin (point)))))
+	    ;; Update or create autoload sections for existing files.
+	    (mapcar 'update-file-autoloads
+		    (directory-files arg t "^[^=].*\\.\\(el\\|c\\)$")))))
        ((file-exists-p arg)
+	(setq generated-autoload-file
+	      (or into-file (expand-file-name autoload-file-name
+					      (file-name-directory arg))))
 	(update-file-autoloads arg))
        (t (error "No such file or directory: %s" arg)))
-      (when (not all-into-one-file)
+      (when (not into-file)
 	(autoload-featurep-protect-autoloads
 	 (autoload-make-feature-name
-	  (file-name-nondirectory (directory-file-name arg))))
+	  (or feature-prefix
+	      (file-name-nondirectory (directory-file-name arg)))))
 	(if force (set-buffer-modified-p
 		   t (find-file-noselect generated-autoload-file)))))
-    (when all-into-one-file
+    (when into-file
       (autoload-featurep-protect-autoloads autoload-feature-name)
       (if force (set-buffer-modified-p
-		 t (find-file-noselect generated-autoload-file))))
+		 t (find-file-noselect into-file))))
     (save-some-buffers t)
     ))
 
 ;;;###autoload
-(defun update-autoloads-from-directory (dir)
-  "Update `generated-autoload-file' with all the current autoloads from DIR.
-This runs `update-file-autoloads' on each .el and .c file in DIR.
-Obsolete autoload entries for files that no longer exist are deleted.
-Note that, if this function is called from `batch-update-directory',
-`generated-autoload-file' was rebound in that function.
-
-You don't really want to be calling this function.  Try using
-`update-autoload-files' instead."
-  (interactive "DUpdate autoloads for directory: ")
-  (setq dir (expand-file-name dir))
-  (let ((simple-dir (file-name-as-directory
-		     (file-name-nondirectory
-		      (directory-file-name dir))))
-	(enable-local-eval nil))
-    (save-excursion
-      (let ((find-file-hooks nil))
-	(set-buffer (find-file-noselect generated-autoload-file)))
-      (goto-char (point-min))
-      (while (search-forward generate-autoload-section-header nil t)
-	(let* ((begin (match-beginning 0))
-	       (form (condition-case ()
-			 (read (current-buffer))
-		       (end-of-file nil)))
-	       (file (nth 3 form)))
-	  (when (and (stringp file)
-		     (string= (file-name-directory file) simple-dir)
-		     (not (file-exists-p
-			   (expand-file-name
-			    (file-name-nondirectory file) dir))))
-	    ;; Remove the obsolete section.
-	    (search-forward generate-autoload-section-trailer)
-	    (delete-region begin (point)))))
-      ;; Update or create autoload sections for existing files.
-      (mapcar 'update-file-autoloads
-	      (directory-files dir t "^[^=].*\\.\\(el\\|c\\)$"))
-      (unless noninteractive
-	(save-buffer)))))
+(defun update-custom-define-files (files-or-dirs feature-prefix
+				   &optional into-file force)
+  "Update all the custom-define files associated with FILES-OR-DIRS.
+Works just like `update-file-autoloads'."
+  (let* ((autoload-feature-suffix "-custom-defines")
+	 (autoload-file-name "custom-defines.el")
+	 (generate-autoload-function #'generate-custom-defines))
+    (update-autoload-files files-or-dirs feature-prefix into-file force)))
 
 (defun autoload-featurep-protect-autoloads (sym)
   (save-excursion
     (set-buffer (find-file-noselect generated-autoload-file))
     (goto-char (point-min))
-    (if (and (not (= (point-min) (point-max)))
-	     (not (looking-at ";;; DO NOT MODIFY THIS FILE")))
-	(progn
-	  (insert ";;; DO NOT MODIFY THIS FILE\n")
-	  (insert "(if (featurep '" sym ")")
-	  (insert " (error \"Feature " sym " already loaded\"))\n")
-	  (goto-char (point-max))
-	  (insert "\n(provide '" sym ")\n")))))
+    (cond ((eq (point-min) (point-max)) nil)
+	  ;; if there's some junk in the file but no sections, just
+	  ;; delete everything.  the junk might be stuff inserted by
+	  ;; an older version of this function.
+	  ((not (search-forward generate-autoload-section-header nil t))
+	   (delete-region (point-min) (point-max)))
+	  (t
+	   (goto-char (point-min))
+	   (when (looking-at ";;; DO NOT MODIFY THIS FILE")
+	     (delete-region (point-min)
+			    (progn
+			      (search-forward generate-autoload-section-header)
+			      (match-beginning 0))))
+	   ;; Determine and set the coding system for the file if under Mule.
+	   ;; If there are any extended characters in the input file, use
+	   ;; `escape-quoted' to make sure that both binary and extended
+	   ;; characters are output properly and distinguished properly.
+	   ;; Otherwise, use `raw-text' for maximum portability with non-Mule
+	   ;; Emacsen.
+	   (if (or (featurep '(not mule)) ;; Don't scan if no Mule support
+		   (progn
+		     (goto-char (point-min))
+		     ;; mrb- There must be a better way than skip-chars-forward
+		     (skip-chars-forward (concat (char-to-string 0) "-"
+						 (char-to-string 255)))
+		     (eq (point) (point-max))))
+	       (setq buffer-file-coding-system 'raw-text-unix)
+	     (setq buffer-file-coding-system 'escape-quoted))
+	   (goto-char (point-min))
+	   (insert ";;; DO NOT MODIFY THIS FILE")
+	   ;; NOTE: XEmacs prior to 21.5.12 or so had a bug in that it
+	   ;; recognized only one of the two magic-cookie styles (the -*- kind)
+	   ;; in find-file, but both of them in load.  We go ahead and put both
+	   ;; in, just to be safe.
+	   (when (eq buffer-file-coding-system 'escape-quoted)
+	     (insert " -*- coding: escape-quoted; -*-
+\(or (featurep 'mule) (error \"Loading this file requires Mule support\"))
+;;;###coding system: escape-quoted"))
+	   (insert "\n(if (featurep '" sym ")")
+	   (insert " (error \"Feature " sym " already loaded\"))\n")
+	   (goto-char (point-max))
+	   (save-excursion
+	     (forward-line -1)
+	     (when (looking-at "(provide")
+	       (delete-region (point) (point-max))))
+	   (unless (bolp) (insert "\n"))
+	   (unless (eq (char-before (1- (point))) ?\^L)
+	     (insert "\^L\n"))
+	   (insert "(provide '" sym ")\n")))))
 
 (defun autoload-make-feature-name (&optional prefix)
   "Generate the feature name to protect this auto-autoloads file from PREFIX.
@@ -864,19 +1123,23 @@
 	    (file-name-directory generated-autoload-file))))
 	 (t (error 'invalid-argument
 		   "Could not compute a feature name")))
-   "-autoloads"))
+   autoload-feature-suffix))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Deprecated entry points
 
 ;; A grep of the core and packages shows use of `batch-update-autoloads'
 ;; by XEmacs.rules, pcomplete, eshell, oort-gnus; `batch-update-directory'
-;; by liece.
+;; by liece.  The other two entry points (`batch-update-one-directory',
+;; `batch-force-update-one-directory') were not used at all.
+;;
+;; All except the first are now history.  liece has been updated.
+;; XEmacs.rules has been updated.  The others will be, eventually.
 
-;; #### these entry points below are a big mess, especially the
-;; first two.  there don't seem to be very many packages that use the
-;; first one (the "all-into-one-file" variety), and do they actually
-;; rely on this functionality? --ben
+;; There don't seem to be very many packages that use the first one (the
+;; "all-into-one-file" variety), and do they actually rely on this
+;; functionality? --ben
+
 ;; but XEmacs.rules does, though maybe it doesn't "rely" on it, and
 ;; modules do now, and that relies on it. --sjt
 
@@ -891,59 +1154,15 @@
 on the command line."
   (unless noninteractive
     (error "batch-update-autoloads is to be used only with -batch"))
-  (update-autoload-files command-line-args-left t)
+  (update-autoload-files command-line-args-left generated-autoload-file)
   (kill-emacs 0))
 
-;;;###autoload
-(defun batch-update-directory ()
-  "Update the autoloads for the directories on the command line.
-Runs `update-file-autoloads' on each file in the given directory, and must
-be used only with -batch.
-
-Uses and removes the first element of `command-line-args-left'."
-  (unless noninteractive
-    (error "batch-update-directory is to be used only with -batch"))
-  (update-autoload-files command-line-args-left)
-  ;; (kill-emacs 0)
-  (setq command-line-args-left nil))
-
-;;;###autoload
-(defun batch-update-one-directory ()
-  "Update the autoloads for a single directory on the command line.
-Runs `update-file-autoloads' on each file in the given directory, and must
-be used only with -batch."
-  (unless noninteractive
-    (error "batch-update-one-directory is to be used only with -batch"))
-  (let ((arg (car command-line-args-left)))
-    (setq command-line-args-left (cdr command-line-args-left))
-    (update-autoload-files (list arg))))
-
-;;;###autoload
-(defun batch-force-update-one-directory ()
-  "Update the autoloads for a single directory on the command line.
-Runs `update-file-autoloads' on each file in the given directory, and must
-be used only with -batch.  Always rewrites the autoloads file, even if
-unchanged.
-
-Uses and removes the first element of `command-line-args-left'."
-  (unless noninteractive
-    (error "batch-force-update-directory is to be used only with -batch"))
-  (let ((arg (car command-line-args-left)))
-    (setq command-line-args-left (cdr command-line-args-left))
-    (update-autoload-files (list arg) nil t)))
-
 ;; Declare obsolescence
 
 (make-obsolete-variable 'autoload-target-directory
   "Don't use this.  Bind `generated-autoload-file' to an absolute path.")
 (make-obsolete 'batch-update-autoloads
 	       'autoload-update-directory-autoloads)
-(make-obsolete 'batch-update-directory
-	       'autoload-update-directory-autoloads)
-(make-obsolete 'batch-update-one-directory
-	       'autoload-update-directory-autoloads)
-(make-obsolete 'batch-force-update-one-directory
-	       'autoload-update-directory-autoloads)
 
 (provide 'autoload)