c20092971f7d17b1e7b6adfdbc10596ac3e5d6bb
[sxemacs] / files.el
1 ;;; files.el --- file input and output commands for SXEmacs.
2
3 ;; Copyright (C) 1985-1987, 1992-1995, 1997 Free Software Foundation, Inc.
4 ;; Copyright (C) 1995 Sun Microsystems.
5
6 ;; Maintainer: SXEmacs Development Team
7 ;; Keywords: extensions, dumped
8
9 ;; This file is part of SXEmacs.
10
11 ;; SXEmacs is free software: you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation, either version 3 of the License, or
14 ;; (at your option) any later version.
15
16 ;; SXEmacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 ;; GNU General Public License for more details.
20
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
23
24 ;;; Synched up with: FSF 20.3 (but diverging)
25 ;;; Warning: Merging this file is tough.  Beware.
26
27 ;;; Commentary:
28
29 ;; This file is dumped with SXEmacs.
30
31 ;; Defines most of XEmacs's file- and directory-handling functions,
32 ;; including basic file visiting, backup generation, link handling,
33 ;; ITS-id version control, load- and write-hook handling, and the like.
34
35 ;;; Code:
36
37 ;; XEmacs: Avoid compilation warnings.
38 (defvar coding-system-for-read)
39 (defvar buffer-file-coding-system)
40 (eval-when-compile
41   (globally-declare-fboundp '(dired-noselect dired)))
42
43
44 (defgroup files nil
45   "Support editing files."
46   :group 'emacs)
47
48 (defgroup backup nil
49   "Backups of edited data files."
50   :group 'files)
51
52 (defgroup find-file nil
53   "Finding and editing files."
54   :group 'files)
55
56
57 ;; XEmacs: In buffer.c
58 ;(defconst delete-auto-save-files t
59 ;  "*Non-nil means delete auto-save file when a buffer is saved or killed.")
60
61 ;; FSF has automount-dir-prefix.  Our directory-abbrev-alist is more general.
62 ;; note: tmp_mnt bogosity conversion is established in paths.el.
63 (defcustom directory-abbrev-alist nil
64   "*Alist of abbreviations for file directories.
65 A list of elements of the form (FROM . TO), each meaning to replace
66 FROM with TO when it appears in a directory name.
67 This replacement is done when setting up the default directory of a
68 newly visited file.  *Every* FROM string should start with \\\\` or ^.
69
70 Use this feature when you have directories which you normally refer to
71 via absolute symbolic links or to eliminate automounter mount points
72 from the beginning of your filenames.  Make TO the name of the link,
73 and FROM the name it is linked to."
74   :type '(repeat (cons :format "%v"
75                        :value ("\\`" . "")
76                        (regexp :tag "From")
77                        (regexp :tag "To")))
78   :group 'find-file)
79
80 (defcustom make-backup-files t
81   "*Non-nil means make a backup of a file the first time it is saved.
82 This can be done by renaming the file or by copying.
83
84 Renaming means that XEmacs renames the existing file so that it is a
85 backup file, then writes the buffer into a new file.  Any other names
86 that the old file had will now refer to the backup file.  The new file
87 is owned by you and its group is defaulted.
88
89 Copying means that XEmacs copies the existing file into the backup
90 file, then writes the buffer on top of the existing file.  Any other
91 names that the old file had will now refer to the new (edited) file.
92 The file's owner and group are unchanged.
93
94 The choice of renaming or copying is controlled by the variables
95 `backup-by-copying', `backup-by-copying-when-linked' and
96 `backup-by-copying-when-mismatch'.  See also `backup-inhibited'."
97   :type 'boolean
98   :group 'backup)
99
100 ;; Do this so that local variables based on the file name
101 ;; are not overridden by the major mode.
102 (defvar backup-inhibited nil
103   "Non-nil means don't make a backup, regardless of the other parameters.
104 This variable is intended for use by making it local to a buffer.
105 But it is local only if you make it local.")
106 (put 'backup-inhibited 'permanent-local t)
107
108 (defcustom backup-by-copying nil
109  "*Non-nil means always use copying to create backup files.
110 See documentation of variable `make-backup-files'."
111  :type 'boolean
112  :group 'backup)
113
114 (defcustom backup-by-copying-when-linked nil
115  "*Non-nil means use copying to create backups for files with multiple names.
116 This causes the alternate names to refer to the latest version as edited.
117 This variable is relevant only if `backup-by-copying' is nil."
118  :type 'boolean
119  :group 'backup)
120
121 (defcustom backup-by-copying-when-mismatch nil
122   "*Non-nil means create backups by copying if this preserves owner or group.
123 Renaming may still be used (subject to control of other variables)
124 when it would not result in changing the owner or group of the file;
125 that is, for files which are owned by you and whose group matches
126 the default for a new file created there by you.
127 This variable is relevant only if `backup-by-copying' is nil."
128   :type 'boolean
129   :group 'backup)
130
131 (defvar backup-enable-predicate
132   #'(lambda (name)
133      (not (or (null name)
134               (string-match "^/tmp/" name)
135               (let ((tmpdir (temp-directory)))
136                 (and tmpdir
137                      (string-match (concat "\\`" (regexp-quote tmpdir) "/")
138                                    tmpdir))))))
139   "Predicate that looks at a file name and decides whether to make backups.
140 Called with an absolute file name as argument, it returns t to enable backup.")
141
142 (defcustom buffer-offer-save nil
143   "*Non-nil in a buffer means offer to save the buffer on exit
144 even if the buffer is not visiting a file.
145 Automatically local in all buffers."
146   :type 'boolean
147   :group 'find-file)
148 (make-variable-buffer-local 'buffer-offer-save)
149
150 ;; FSF uses normal defconst
151 (defvaralias 'find-file-visit-truename 'find-file-use-truenames)
152 (defvaralias 'find-file-existing-other-name 'find-file-compare-truenames)
153
154 (defcustom revert-without-query nil
155   "*Specify which files should be reverted without query.
156 The value is a list of regular expressions.
157 If the file name matches one of these regular expressions,
158 then `revert-buffer' reverts the file without querying
159 if the file has changed on disk and you have not edited the buffer."
160   :type '(repeat (regexp ""))
161   :group 'find-file)
162
163 (defvar buffer-file-number nil
164   "The device number and file number of the file visited in the current buffer.
165 The value is a list of the form (FILENUM DEVNUM).
166 This pair of numbers uniquely identifies the file.
167 If the buffer is visiting a new file, the value is nil.")
168 (make-variable-buffer-local 'buffer-file-number)
169 (put 'buffer-file-number 'permanent-local t)
170
171 (defvar buffer-file-numbers-unique (not (memq system-type '(windows-nt)))
172   "Non-nil means that buffer-file-number uniquely identifies files.")
173
174 (defcustom file-precious-flag nil
175   "*Non-nil means protect against I/O errors while saving files.
176 Some modes set this non-nil in particular buffers.
177
178 This feature works by writing the new contents into a temporary file
179 and then renaming the temporary file to replace the original.
180 In this way, any I/O error in writing leaves the original untouched,
181 and there is never any instant where the file is nonexistent.
182
183 Note that this feature forces backups to be made by copying.
184 Yet, at the same time, saving a precious file
185 breaks any hard links between it and other files."
186   :type 'boolean
187   :group 'backup)
188
189 (defcustom version-control nil
190   "*Control use of version numbers for backup files.
191 t means make numeric backup versions unconditionally.
192 nil means make them for files that have some already.
193 `never' means do not make them."
194   :type 'boolean
195   :group 'backup
196   :group 'vc)
197
198 ;; This is now defined in efs.
199 ;(defvar dired-kept-versions 2
200 ;  "*When cleaning directory, number of versions to keep.")
201
202 (defcustom delete-old-versions (when noninteractive 'leave)
203   "*If t, delete excess backup versions silently.
204 If nil, ask confirmation.  Any other value prevents any trimming."
205   :type '(choice (const :tag "Delete" t)
206                  (const :tag "Ask" nil)
207                  (sexp :tag "Leave" :format "%t\n" other))
208   :group 'backup)
209
210 (defcustom kept-old-versions 2
211   "*Number of oldest versions to keep when a new numbered backup is made."
212   :type 'integer
213   :group 'backup)
214
215 (defcustom kept-new-versions 2
216   "*Number of newest versions to keep when a new numbered backup is made.
217 Includes the new backup.  Must be > 0"
218   :type 'integer
219   :group 'backup)
220
221 (defcustom require-final-newline nil
222   "*Value of t says silently ensure a file ends in a newline when it is saved.
223 Non-nil but not t says ask user whether to add a newline when there isn't one.
224 nil means don't add newlines."
225   :type '(choice (const :tag "Off" nil)
226                  (const :tag "Add" t)
227                  (sexp :tag "Ask" :format "%t\n" ask))
228   :group 'editing-basics)
229
230 (defcustom auto-save-default t
231   "*Non-nil says by default do auto-saving of every file-visiting buffer."
232   :type 'boolean
233   :group 'auto-save)
234
235 (defcustom auto-save-visited-file-name nil
236   "*Non-nil says auto-save a buffer in the file it is visiting, when practical.
237 Normally auto-save files are written under other names."
238   :type 'boolean
239   :group 'auto-save)
240
241 (defcustom save-abbrevs nil
242   "*Non-nil means save word abbrevs too when files are saved.
243 Loading an abbrev file sets this to t."
244   :type 'boolean
245   :group 'abbrev)
246
247 (defcustom find-file-run-dired t
248   "*Non-nil says run dired if `find-file' is given the name of a directory."
249   :type 'boolean
250   :group 'find-file)
251
252 ;;;It is not useful to make this a local variable.
253 ;;;(put 'find-file-not-found-hooks 'permanent-local t)
254 (defvar find-file-not-found-hooks nil
255   "List of functions to be called for `find-file' on nonexistent file.
256 These functions are called as soon as the error is detected.
257 `buffer-file-name' is already set up.
258 The functions are called in the order given until one of them returns non-nil.")
259
260 ;;;It is not useful to make this a local variable.
261 ;;;(put 'find-file-hooks 'permanent-local t)
262 (defvar find-file-hooks nil
263   "List of functions to be called after a buffer is loaded from a file.
264 The buffer's local variables (if any) will have been processed before the
265 functions are called.")
266
267 (defvar write-file-hooks nil
268   "List of functions to be called before writing out a buffer to a file.
269 If one of them returns non-nil, the file is considered already written
270 and the rest are not called.
271 These hooks are considered to pertain to the visited file.
272 So this list is cleared if you change the visited file name.
273 See also `write-contents-hooks' and `continue-save-buffer'.")
274 ;;; However, in case someone does make it local...
275 (put 'write-file-hooks 'permanent-local t)
276
277 (defvar local-write-file-hooks nil
278   "Just like `write-file-hooks', except intended for per-buffer use.
279 The functions in this list are called before the ones in
280 `write-file-hooks'.
281
282 This variable is meant to be used for hooks that have to do with a
283 particular visited file.  Therefore, it is a permanent local, so that
284 changing the major mode does not clear it.  However, calling
285 `set-visited-file-name' does clear it.")
286 (make-variable-buffer-local 'local-write-file-hooks)
287 (put 'local-write-file-hooks 'permanent-local t)
288
289
290 ;; #### think about this (added by Sun).
291 (put 'after-set-visited-file-name-hooks 'permanent-local t)
292 (defvar after-set-visited-file-name-hooks nil
293   "List of functions to be called after \\[set-visited-file-name]
294 or during \\[write-file].
295 You can use this hook to restore local values of `write-file-hooks',
296 `after-save-hook', and `revert-buffer-function', which pertain
297 to a specific file and therefore are normally killed by a rename.
298 Put hooks pertaining to the buffer contents on `write-contents-hooks'
299 and `revert-buffer-insert-file-contents-function'.")
300
301 (defvar write-contents-hooks nil
302   "List of functions to be called before writing out a buffer to a file.
303 If one of them returns non-nil, the file is considered already written
304 and the rest are not called.
305 These hooks are considered to pertain to the buffer's contents,
306 not to the particular visited file; thus, `set-visited-file-name' does
307 not clear this variable, but changing the major mode does clear it.
308 See also `write-file-hooks' and `continue-save-buffer'.")
309
310 ;;  XEmacs addition
311 ;;  Energize needed this to hook into save-buffer at a lower level; we need
312 ;;  to provide a new output method, but don't want to have to duplicate all
313 ;;  of the backup file and file modes logic.that does not occur if one uses
314 ;;  a write-file-hook which returns non-nil.
315 (put 'write-file-data-hooks 'permanent-local t)
316 (defvar write-file-data-hooks nil
317   "List of functions to be called to put the bytes on disk.
318 These functions receive the name of the file to write to as argument.
319 The default behavior is to call
320   (write-region (point-min) (point-max) filename nil t)
321 If one of them returns non-nil, the file is considered already written
322 and the rest are not called.
323 These hooks are considered to pertain to the visited file.
324 So this list is cleared if you change the visited file name.
325 See also `write-file-hooks'.")
326
327 (defcustom enable-local-variables t
328   "*Control use of local-variables lists in files you visit.
329 The value can be t, nil or something else.
330 A value of t means local-variables lists are obeyed;
331 nil means they are ignored; anything else means query.
332
333 The command \\[normal-mode] always obeys local-variables lists
334 and ignores this variable."
335   :type '(choice (const :tag "Obey" t)
336                  (const :tag "Ignore" nil)
337                  (sexp :tag "Query" :format "%t\n" other))
338   :group 'find-file)
339
340 (defcustom enable-local-eval 'maybe
341   "*Control processing of the \"variable\" `eval' in a file's local variables.
342 The value can be t, nil or something else.
343 A value of t means obey `eval' variables;
344 nil means ignore them; anything else means query.
345
346 The command \\[normal-mode] always obeys local-variables lists
347 and ignores this variable."
348   :type '(choice (const :tag "Obey" t)
349                  (const :tag "Ignore" nil)
350                  (sexp :tag "Query" :format "%t\n" other))
351   :group 'find-file)
352
353 ;;; SXEmacs addition
354 (defcustom find-file-magic-files-alist
355   '((file-directory-p . find-file-try-dired-noselect))
356   "Alist where each element is in form \(PREDICATE . FUNCTION-OF-ONE-ARGUMENT\).
357 FUNCTION-OF-ONE-ARGUMENT must return some buffer."
358   :type 'alist
359   :group 'find-file)
360
361 ;; Avoid losing in versions where CLASH_DETECTION is disabled.
362 (or (fboundp 'lock-buffer)
363     (defalias 'lock-buffer 'ignore))
364 (or (fboundp 'unlock-buffer)
365     (defalias 'unlock-buffer 'ignore))
366 \f
367 ;;FSFmacs bastardized ange-ftp cruft
368 ;; This hook function provides support for ange-ftp host name
369 ;; completion.  It runs the usual ange-ftp hook, but only for
370 ;; completion operations.  Having this here avoids the need
371 ;; to load ange-ftp when it's not really in use.
372 ;(defun ange-ftp-completion-hook-function (op &rest args)
373 ;  (if (memq op '(file-name-completion file-name-all-completions))
374 ;      (apply 'ange-ftp-hook-function op args)
375 ;    (let ((inhibit-file-name-handlers
376 ;          (cons 'ange-ftp-completion-hook-function
377 ;                (and (eq inhibit-file-name-operation op)
378 ;                     inhibit-file-name-handlers)))
379 ;         (inhibit-file-name-operation op))
380 ;      (apply op args))
381
382 (defun convert-standard-filename (filename)
383   "Convert a standard file's name to something suitable for the current OS."
384   (if (eq system-type 'windows-nt)
385       (let ((name (copy-sequence filename))
386             (start 0))
387         ;; leave ':' if part of drive specifier
388         (if (and (> (length name) 1)
389                  (eq (aref name 1) ?:))
390             (setq start 2))
391         ;; destructively replace invalid filename characters with !
392         (while (string-match "[?*:<>|\"\000-\037]" name start)
393           (aset name (match-beginning 0) ?!)
394           (setq start (match-end 0)))
395         ;; FSF: [convert directory separators to Windows format ...]
396         ;; unneeded in XEmacs.
397         name)
398     filename))
399
400 \f
401 (defun pwd ()
402   "Show the current default directory."
403   (interactive nil)
404   (message "Directory %s" default-directory))
405
406 (defvar cd-path nil
407   "Value of the CDPATH environment variable, as a list.
408 Not actually set up until the first time you use it.")
409
410 (defvar cdpath-previous nil
411   "Prior value of the CDPATH environment variable.")
412
413 (defun parse-colon-path (cd-path)
414   "Explode a colon-separated search path into a list of directory names.
415
416 If you think you want to use this, you probably don't.  This function
417 is provided for backward compatibility.  A more robust implementation
418 of the same functionality is available as `split-path', which see."
419   (and cd-path
420        (let (cd-list (cd-start 0) cd-colon)
421          (setq cd-path (concat cd-path path-separator))
422          (while (setq cd-colon (string-match path-separator cd-path cd-start))
423            (setq cd-list
424                  (nconc cd-list
425                         (list (if (= cd-start cd-colon)
426                                    nil
427                                 (substitute-in-file-name
428                                  (file-name-as-directory
429                                   (substring cd-path cd-start cd-colon)))))))
430            (setq cd-start (+ cd-colon 1)))
431          cd-list)))
432
433 (defun cd-absolute (dir)
434   "Change current directory to given absolute file name DIR."
435   ;; Put the name into directory syntax now,
436   ;; because otherwise expand-file-name may give some bad results.
437   (setq dir (file-name-as-directory dir))
438   ;; XEmacs change: stig@hackvan.com
439   (if find-file-use-truenames
440       (setq dir (file-truename dir)))
441   (setq dir (abbreviate-file-name (expand-file-name dir)))
442   (cond ((not (file-directory-p dir))
443          (error "%s is not a directory" dir))
444         ;; this breaks ange-ftp, which doesn't (can't?) overload `file-executable-p'.
445         ;;((not (file-executable-p dir))
446         ;; (error "Cannot cd to %s:  Permission denied" dir))
447         (t
448          (setq default-directory dir))))
449
450 (defun cd (dir)
451   "Make DIR become the current buffer's default directory.
452 If your environment includes a `CDPATH' variable, try each one of that
453 colon-separated list of directories when resolving a relative directory name."
454   (interactive
455    ;; XEmacs change? (read-file-name => read-directory-name)
456    (list (read-directory-name "Change default directory: "
457                               default-directory default-directory
458                               (and (member cd-path '(nil ("./")))
459                                    (null (getenv "CDPATH"))))))
460   (if (file-name-absolute-p dir)
461       (cd-absolute (expand-file-name dir))
462     ;; XEmacs
463     (unless (and cd-path (equal (getenv "CDPATH") cdpath-previous))
464       ;;#### Unix-specific
465       (let ((trypath (parse-colon-path
466                       (setq cdpath-previous (getenv "CDPATH")))))
467         (setq cd-path (or trypath (list "./")))))
468     (or (catch 'found
469           (mapcar #'(lambda (x)
470                         (let ((f (expand-file-name (concat x dir))))
471                           (if (file-directory-p f)
472                               (progn
473                                 (cd-absolute f)
474                                 (throw 'found t)))))
475                   cd-path)
476           nil)
477         ;; jwz: give a better error message to those of us with the
478         ;; good taste not to use a kludge like $CDPATH.
479         (if (equal cd-path '("./"))
480             (error "No such directory: %s" (expand-file-name dir))
481           (error "Directory not found in $CDPATH: %s" dir)))))
482
483 (defun load-file (file)
484   "Load the Lisp file named FILE."
485   (interactive "fLoad file: ")
486   (load (expand-file-name file) nil nil t))
487
488 ; We now dump utils/lib-complete.el which has improved versions of this.
489 ;(defun load-library (library)
490 ;  "Load the library named LIBRARY.
491 ;This is an interface to the function `load'."
492 ;  (interactive "sLoad library: ")
493 ;  (load library))
494 ;
495 ;(defun find-library (library)
496 ;  "Find the library of Lisp code named LIBRARY.
497 ;This searches `load-path' for a file named either \"LIBRARY\" or \"LIBRARY.el\"."
498 ;  (interactive "sFind library file: ")
499 ;  (let ((f (locate-file library load-path ":.el:")))
500 ;    (if f
501 ;        (find-file f)
502 ;        (error "Couldn't locate library %s" library))))
503
504 (defun file-local-copy (file &optional buffer)
505   "Copy the file FILE into a temporary file on this machine.
506 Returns the name of the local copy, or nil, if FILE is directly
507 accessible."
508   (let ((handler (find-file-name-handler file 'file-local-copy)))
509     (if handler
510         (funcall handler 'file-local-copy file)
511       nil)))
512
513 ;; XEmacs change block
514 ; We have this in C and use the realpath() system call.
515
516 ;(defun file-truename (filename &optional counter prev-dirs)
517 ; [... lots of code snipped ...]
518 ;    filename))
519
520 ;; XEmacs addition.  Called from `insert-file-contents-internal'
521 ;; at the appropriate time.
522 (defun compute-buffer-file-truename (&optional buffer)
523   "Recompute BUFFER's value of `buffer-file-truename'
524 based on the current value of `buffer-file-name'.
525 BUFFER defaults to the current buffer if unspecified."
526   (save-excursion
527     (set-buffer (or buffer (current-buffer)))
528     (cond ((null buffer-file-name)
529            (setq buffer-file-truename nil))
530           ((setq buffer-file-truename (file-truename buffer-file-name))
531            ;; it exists, we're done.
532            nil)
533           (t
534            ;; the file doesn't exist, but maybe the directory does.
535            (let* ((dir (file-name-directory buffer-file-name))
536                   (truedir (file-truename dir)))
537              (if truedir (setq dir truedir))
538              (setq buffer-file-truename
539                    (expand-file-name (file-name-nondirectory buffer-file-name)
540                                      dir)))))
541     (if (and find-file-use-truenames buffer-file-truename)
542         (setq buffer-file-name (abbreviate-file-name buffer-file-truename)
543               default-directory (file-name-directory buffer-file-name)))
544     buffer-file-truename))
545 ;; End XEmacs change block
546
547 (defun file-chase-links (filename)
548   "Chase links in FILENAME until a name that is not a link.
549 Does not examine containing directories for links,
550 unlike `file-truename'."
551   (let (tem (count 100) (newname filename))
552     (while (setq tem (file-symlink-p newname))
553       (save-match-data
554         (if (= count 0)
555             (error "Apparent cycle of symbolic links for %s" filename))
556         ;; In the context of a link, `//' doesn't mean what XEmacs thinks.
557         (while (string-match "//+" tem)
558           (setq tem (concat (substring tem 0 (1+ (match-beginning 0)))
559                             (substring tem (match-end 0)))))
560         ;; Handle `..' by hand, since it needs to work in the
561         ;; target of any directory symlink.
562         ;; This code is not quite complete; it does not handle
563         ;; embedded .. in some cases such as ./../foo and foo/bar/../../../lose.
564         (while (string-match #r"\`\.\./" tem) ;#### Unix specific
565           (setq tem (substring tem 3))
566           (setq newname (file-name-as-directory
567                          ;; Do the .. by hand.
568                          (directory-file-name
569                           (file-name-directory
570                            ;; Chase links in the default dir of the symlink.
571                            (file-chase-links
572                             (directory-file-name
573                              (file-name-directory newname))))))))
574         (setq newname (expand-file-name tem (file-name-directory newname)))
575         (setq count (1- count))))
576     newname))
577 \f
578 (defun switch-to-other-buffer (arg)
579   "Switch to the previous buffer.  With a numeric arg, n, switch to the nth
580 most recent buffer.  With an arg of 0, buries the current buffer at the
581 bottom of the buffer stack."
582   (interactive "p")
583   (if (eq arg 0)
584       (bury-buffer (current-buffer)))
585   (switch-to-buffer
586    (if (<= arg 1) (other-buffer (current-buffer))
587      (nth (1+ arg) (buffer-list)))))
588
589 (defun switch-to-buffer-other-window (buffer)
590   "Select buffer BUFFER in another window."
591   (interactive "BSwitch to buffer in other window: ")
592   (let ((pop-up-windows t))
593     ;; XEmacs: this used to have (selected-frame) as the third argument,
594     ;; but this is obnoxious.  If the user wants the buffer in a
595     ;; different frame, then it should be this way.
596
597     ;; Change documented above undone --mrb
598     (pop-to-buffer buffer t (selected-frame))))
599
600 (defun switch-to-buffer-other-frame (buffer)
601   "Switch to buffer BUFFER in a newly-created frame."
602   (interactive "BSwitch to buffer in other frame: ")
603   (let* ((name (get-frame-name-for-buffer buffer))
604          (frame (make-frame (if name
605                                   (list (cons 'name (symbol-name name)))))))
606     (pop-to-buffer buffer t frame)
607     (make-frame-visible frame)
608     buffer))
609
610 (defun find-file (filename &optional codesys)
611   "Edit file FILENAME.
612 Switch to a buffer visiting file FILENAME,
613 creating one if none already exists.
614 Under XEmacs/Mule, optional second argument specifies the
615 coding system to use when decoding the file.  Interactively,
616 with a prefix argument, you will be prompted for the coding system."
617   (interactive "FFind file: \nZCoding system: ")
618   (if codesys
619       (let ((coding-system-for-read
620              (get-coding-system codesys)))
621         (switch-to-buffer (find-file-noselect filename)))
622     (switch-to-buffer (find-file-noselect filename))))
623
624 (defun find-file-other-window (filename &optional codesys)
625   "Edit file FILENAME, in another window.
626 May create a new window, or reuse an existing one.
627 See the function `display-buffer'.
628 Under XEmacs/Mule, optional second argument specifies the
629 coding system to use when decoding the file.  Interactively,
630 with a prefix argument, you will be prompted for the coding system."
631   (interactive "FFind file in other window: \nZCoding system: ")
632   (if codesys
633       (let ((coding-system-for-read
634              (get-coding-system codesys)))
635         (switch-to-buffer-other-window (find-file-noselect filename)))
636     (switch-to-buffer-other-window (find-file-noselect filename))))
637
638 (defun find-file-other-frame (filename &optional codesys)
639   "Edit file FILENAME, in a newly-created frame.
640 Under XEmacs/Mule, optional second argument specifies the
641 coding system to use when decoding the file.  Interactively,
642 with a prefix argument, you will be prompted for the coding system."
643   (interactive "FFind file in other frame: \nZCoding system: ")
644   (if codesys
645       (let ((coding-system-for-read
646              (get-coding-system codesys)))
647         (switch-to-buffer-other-frame (find-file-noselect filename)))
648     (switch-to-buffer-other-frame (find-file-noselect filename))))
649
650 (defun find-file-read-only (filename &optional codesys)
651   "Edit file FILENAME but don't allow changes.
652 Like \\[find-file] but marks buffer as read-only.
653 Use \\[toggle-read-only] to permit editing.
654 Under XEmacs/Mule, optional second argument specifies the
655 coding system to use when decoding the file.  Interactively,
656 with a prefix argument, you will be prompted for the coding system."
657   (interactive "fFind file read-only: \nZCoding system: ")
658   (if codesys
659       (let ((coding-system-for-read
660              (get-coding-system codesys)))
661         (find-file filename))
662     (find-file filename))
663   (setq buffer-read-only t)
664   (current-buffer))
665
666 (defun find-file-read-only-other-window (filename &optional codesys)
667   "Edit file FILENAME in another window but don't allow changes.
668 Like \\[find-file-other-window] but marks buffer as read-only.
669 Use \\[toggle-read-only] to permit editing.
670 Under XEmacs/Mule, optional second argument specifies the
671 coding system to use when decoding the file.  Interactively,
672 with a prefix argument, you will be prompted for the coding system."
673   (interactive "fFind file read-only other window: \nZCoding system: ")
674   (if codesys
675       (let ((coding-system-for-read
676              (get-coding-system codesys)))
677         (find-file-other-window filename))
678     (find-file-other-window filename))
679   (setq buffer-read-only t)
680   (current-buffer))
681
682 (defun find-file-read-only-other-frame (filename &optional codesys)
683   "Edit file FILENAME in another frame but don't allow changes.
684 Like \\[find-file-other-frame] but marks buffer as read-only.
685 Use \\[toggle-read-only] to permit editing.
686 Under XEmacs/Mule, optional second argument specifies the
687 coding system to use when decoding the file.  Interactively,
688 with a prefix argument, you will be prompted for the coding system."
689   (interactive "fFind file read-only other frame: \nZCoding system: ")
690   (if codesys
691       (let ((coding-system-for-read
692              (get-coding-system codesys)))
693         (find-file-other-frame filename))
694     (find-file-other-frame filename))
695   (setq buffer-read-only t)
696   (current-buffer))
697
698 (defun find-alternate-file-other-window (filename &optional codesys)
699   "Find file FILENAME as a replacement for the file in the next window.
700 This command does not select that window.
701 Under XEmacs/Mule, optional second argument specifies the
702 coding system to use when decoding the file.  Interactively,
703 with a prefix argument, you will be prompted for the coding system."
704   (interactive
705    (save-selected-window
706      (other-window 1)
707      (let ((file buffer-file-name)
708            (file-name nil)
709            (file-dir nil))
710        (and file
711             (setq file-name (file-name-nondirectory file)
712                   file-dir (file-name-directory file)))
713        (list (read-file-name
714               "Find alternate file: " file-dir nil nil file-name)
715              (if (and current-prefix-arg (featurep 'mule))
716                  (read-coding-system "Coding-system: "))))))
717   (if (one-window-p)
718       (find-file-other-window filename)
719     (save-selected-window
720       (other-window 1)
721       (find-alternate-file filename codesys))))
722
723 (defun find-alternate-file (filename &optional codesys)
724   "Find file FILENAME, select its buffer, kill previous buffer.
725 If the current buffer now contains an empty file that you just visited
726 \(presumably by mistake), use this command to visit the file you really want.
727 Under XEmacs/Mule, optional second argument specifies the
728 coding system to use when decoding the file.  Interactively,
729 with a prefix argument, you will be prompted for the coding system."
730   (interactive
731    (let ((file buffer-file-name)
732          (file-name nil)
733          (file-dir nil))
734      (and file
735           (setq file-name (file-name-nondirectory file)
736                 file-dir (file-name-directory file)))
737      (list (read-file-name
738             "Find alternate file: " file-dir nil nil file-name)
739            (if (and current-prefix-arg (featurep 'mule))
740                (read-coding-system "Coding-system: ")))))
741   (and (buffer-modified-p) (buffer-file-name)
742      &nb