📄 fileio.c
字号:
if (desc < 0) { /* If we can't open the temporary file, try creating a new version of the original file. VMS "creat" creates a new version rather than truncating an existing file. */ fn = fname; fname = 0; desc = creat (fn, 0666); if (desc < 0) { /* We can't make a new version; try to truncate and rewrite existing version if any. */ vms_truncate (fn); desc = open (fn, O_RDWR); } } } else desc = creat (fn, 0666); }#else /* not VMS */ desc = creat (fn, 0666);#endif /* not VMS */ if (desc < 0) {#ifdef CLASH_DETECTION save_errno = errno; if (!auto_saving) unlock_file (filename); errno = save_errno;#endif /* CLASH_DETECTION */ report_file_error ("Opening output file", Fcons (filename, Qnil)); } record_unwind_protect (close_file_unwind, make_number (desc)); if (!NULL (append)) if (lseek (desc, (off_t) 0, 2) < 0) {#ifdef CLASH_DETECTION if (!auto_saving) unlock_file (filename);#endif /* CLASH_DETECTION */ report_file_error ("Lseek error", Fcons (filename, Qnil)); }#ifdef VMS/* * Kludge Warning: The VMS C RTL likes to insert carriage returns * if we do writes that don't end with a carriage return. Furthermore * it cannot handle writes of more then 16K. The modified * version of "sys_write" in SYSDEP.C (see comment there) copes with * this EXCEPT for the last record (iff it doesn't end with a carriage * return). This implies that if your buffer doesn't end with a carriage * return, you get one free... tough. However it also means that if * we make two calls to sys_write (a la the following code) you can * get one at the gap as well. The easiest way to fix this (honest) * is to move the gap to the next newline (or the end of the buffer). * Thus this change. * * Yech! */ if (GPT > BEG && GPT_ADDR[-1] != '\n') move_gap (find_next_newline (GPT, 1));#endif failure = 0; if (XINT (start) != XINT (end)) { if (XINT (start) < GPT) { register int end1 = XINT (end); tem = XINT (start); failure = 0 > e_write (desc, &FETCH_CHAR (tem), min (GPT, end1) - tem); save_errno = errno; } if (XINT (end) > GPT && !failure) { tem = XINT (start); tem = max (tem, GPT); failure = 0 > e_write (desc, &FETCH_CHAR (tem), XINT (end) - tem); save_errno = errno; } }#ifndef USG#ifndef VMS#ifndef BSD4_1#ifndef alliant /* trinkle@cs.purdue.edu says fsync can return EBUSY on alliant, for no visible reason. */ /* Note fsync appears to change the modtime on BSD4.2 (both vax and sun). Disk full in NFS may be reported here. */ if (fsync (desc) < 0) failure = 1, save_errno = errno;#endif#endif#endif#endif#if 0 /* Spurious "file has changed on disk" warnings have been observed on Sun 3 as well. Maybe close changes the modtime with nfs as well. */ /* On VMS and APOLLO, must do the stat after the close since closing changes the modtime. */#ifndef VMS#ifndef APOLLO /* Recall that #if defined does not work on VMS. */#define FOO fstat (desc, &st);#endif#endif#endif /* 0 */ /* NFS can report a write failure now. */ if (close (desc) < 0) failure = 1, save_errno = errno;#ifdef VMS /* If we wrote to a temporary name and had no errors, rename to real name. */ if (fname) { if (!failure) failure = (rename (fn, fname) != 0), save_errno = errno; fn = fname; }#endif /* VMS */#ifndef FOO stat (fn, &st);#endif /* Discard the unwind protect */ specpdl_ptr = specpdl + count;#ifdef CLASH_DETECTION if (!auto_saving) unlock_file (filename);#endif /* CLASH_DETECTION */ /* Do this before reporting IO error to avoid a "file has changed on disk" warning on next attempt to save. */ if (EQ (visit, Qt)) current_buffer->modtime = st.st_mtime; if (failure) error ("IO error writing %s: %s", fn, err_str (save_errno)); if (EQ (visit, Qt)) { current_buffer->save_modified = MODIFF; XFASTINT (current_buffer->save_length) = Z - BEG; current_buffer->filename = filename; } else if (!NULL (visit)) return Qnil; if (!auto_saving) message ("Wrote %s", fn); return Qnil;}inte_write (desc, addr, len) int desc; register char *addr; register int len;{ char buf[16 * 1024]; register char *p, *end; if (!EQ (current_buffer->selective_display, Qt)) return write (desc, addr, len) - len; else { p = buf; end = p + sizeof buf; while (len--) { if (p == end) { if (write (desc, buf, sizeof buf) != sizeof buf) return -1; p = buf; } *p = *addr++; if (*p++ == '\015') p[-1] = '\n'; } if (p != buf) if (write (desc, buf, p - buf) != p - buf) return -1; } return 0;}DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime, Sverify_visited_file_modtime, 1, 1, 0, "Return t if last mod time of BUF's visited file matches what BUF records.\n\This means that the file has not been changed since it was visited or saved.") (buf) Lisp_Object buf;{ struct buffer *b; struct stat st; CHECK_BUFFER (buf, 0); b = XBUFFER (buf); if (XTYPE (b->filename) != Lisp_String) return Qt; if (b->modtime == 0) return Qt; if (stat (XSTRING (b->filename)->data, &st) < 0) { /* If the file doesn't exist now and didn't exist before, we say that it isn't modified, provided the error is a tame one. */ if (errno == ENOENT || errno == EACCES || errno == ENOTDIR) st.st_mtime = -1; else st.st_mtime = 0; } if (st.st_mtime == b->modtime /* If both are positive, accept them if they are off by one second. */ || (st.st_mtime > 0 && b->modtime > 0 && (st.st_mtime == b->modtime + 1 || st.st_mtime == b->modtime - 1))) return Qt; return Qnil;}DEFUN ("clear-visited-file-modtime", Fclear_visited_file_modtime, Sclear_visited_file_modtime, 0, 0, 0, "Clear out records of last mod time of visited file.\n\Next attempt to save will certainly not complain of a discrepancy.") (){ current_buffer->modtime = 0; return Qnil;}Lisp_Objectauto_save_error (){ unsigned char *name = XSTRING (current_buffer->name)->data; bell (); message ("Autosaving...error for %s", name); Fsleep_for (make_number (1)); message ("Autosaving...error!for %s", name); Fsleep_for (make_number (1)); message ("Autosaving...error for %s", name); Fsleep_for (make_number (1)); return Qnil;}Lisp_Objectauto_save_1 (){ return Fwrite_region (Qnil, Qnil, current_buffer->auto_save_file_name, Qnil, Qlambda);}DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 1, "", "Auto-save all buffers that need it.\n\This is all buffers that have auto-saving enabled\n\and are changed since last auto-saved.\n\Auto-saving writes the buffer into a file\n\so that your editing is not lost if the system crashes.\n\This file is not the file you visited; that changes only when you save.\n\n\Non-nil argument means do not print any message if successful.") (nomsg) Lisp_Object nomsg;{ struct buffer *old = current_buffer, *b; Lisp_Object tail, buf; int auto_saved = 0; int tried = 0; char *omessage = echo_area_contents; /* No GCPRO needed, because (when it matters) all Lisp_Object variables point to non-strings reached from Vbuffer_alist. */ auto_saving = 1; if (minibuf_level) nomsg = Qt; for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons; tail = XCONS (tail)->cdr) { buf = XCONS (XCONS (tail)->car)->cdr; b = XBUFFER (buf); /* Check for auto save enabled and file changed since last auto save and file changed since last real save. */ if (XTYPE (b->auto_save_file_name) == Lisp_String && b->save_modified < BUF_MODIFF (b) && b->auto_save_modified < BUF_MODIFF (b)) { /* If we at least consider a buffer for auto-saving, don't try again for a suitable time. */ tried++; if ((XFASTINT (b->save_length) * 10 > (BUF_Z (b) - BUF_BEG (b)) * 13) /* A short file is likely to change a large fraction; spare the user annoying messages. */ && XFASTINT (b->save_length) > 5000 /* These messages are frequent and annoying for `*mail*'. */ && !EQ (b->filename, Qnil)) { /* It has shrunk too much; don't checkpoint. */ message ("Buffer %s has shrunk a lot; not autosaving it", XSTRING (b->name)->data); Fsleep_for (make_number (1)); continue; } set_buffer_internal (b); if (!auto_saved && NULL (nomsg)) message1 ("Auto-saving..."); internal_condition_case (auto_save_1, Qt, auto_save_error); auto_saved++; b->auto_save_modified = BUF_MODIFF (b); XFASTINT (current_buffer->save_length) = Z - BEG; set_buffer_internal (old); } } if (tried) record_auto_save (); if (auto_saved && NULL (nomsg)) message1 (omessage ? omessage : "Auto-saving...done"); auto_saving = 0; return Qnil;}DEFUN ("set-buffer-auto-saved", Fset_buffer_auto_saved, Sset_buffer_auto_saved, 0, 0, 0, "Mark current buffer as auto-saved with its current text.\n\No auto-save file will be written until the buffer changes again.") (){ current_buffer->auto_save_modified = MODIFF; XFASTINT (current_buffer->save_length) = Z - BEG; return Qnil;}DEFUN ("recent-auto-save-p", Frecent_auto_save_p, Srecent_auto_save_p, 0, 0, 0, "Return t if buffer has been auto-saved since last read in or saved.") (){ return (current_buffer->save_modified < current_buffer->auto_save_modified) ? Qt : Qnil;}/* Reading and completing file names */extern Lisp_Object Ffile_name_completion (), Ffile_name_all_completions ();DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_internal, 3, 3, 0, "Internal subroutine for read-file-name. Do not call this.") (string, dir, action) Lisp_Object string, dir, action; /* action is nil for complete, t for return list of completions, lambda for verify final value */{ Lisp_Object name, specdir, realdir, val; if (XSTRING (string)->size == 0) { name = string; realdir = dir; if (EQ (action, Qlambda)) return Qnil; } else { string = Fsubstitute_in_file_name (string); name = Ffile_name_nondirectory (string); realdir = Ffile_name_directory (string); if (NULL (realdir)) realdir = dir; else realdir = Fexpand_file_name (realdir, dir); } if (NULL (action)) { specdir = Ffile_name_directory (string); val = Ffile_name_completion (name, realdir); if (XTYPE (val) != Lisp_String) return (val); if (!NULL (specdir)) val = concat2 (specdir, val);#ifndef VMS { register unsigned char *old, *new; register int n; int osize, count; osize = XSTRING (val)->size; /* Quote "$" as "$$" to get it past substitute-in-file-name */ for (n = osize, count = 0, old = XSTRING (val)->data; n > 0; n--) if (*old++ == '$') count++; if (count > 0) { old = XSTRING (val)->data; val = Fmake_string (make_number (osize + count), make_number (0)); new = XSTRING (val)->data; for (n = osize; n > 0; n--) if (*old != '$') *new++ = *old++; else { *new++ = '$'; *new++ = '$'; old++; } } }#endif /* Not VMS */ return (val); } if (EQ (action, Qt)) return Ffile_name_all_completions (name, realdir); /* Only other case actually used is ACTION = lambda */#ifdef VMS /* Supposedly this helps commands such as `cd' that read directory names, but can someone explain how it helps them? -- RMS */ if (XSTRING (name)->size == 0) return Qt;#endif /* VMS */ return Ffile_exists_p (string);}DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 4, 0, "Read file name, prompting with PROMPT and completing in directory DIR.\n\Value is not expanded! You must call expand-file-name yourself.\n\Default name to DEFAULT if user enters a null string.\n\Fourth arg MUSTMATCH non-nil means require existing file's name.\n\ Non-nil and non-t means also require confirmation after completion.\n\DIR defaults to current buffer's directory default.") (prompt, dir, defalt, mustmatch) Lisp_Object prompt, dir, defalt, mustmatch;{ Lisp_Object val, insdef, tem; struct gcpro gcpro1, gcpro2; register char *homedir; int count; if (NULL (dir)) dir = current_buffer->directory; if (NULL (defalt)) defalt = current_buffer->filename; /* If dir starts with user's homedir, change that to ~. */ homedir = (char *) egetenv ("HOME"); if (homedir != 0 && XTYPE (dir) == Lisp_String && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir)) && XSTRING (dir)->data[strlen (homedir)] == '/') { dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1, XSTRING (dir)->size - strlen (homedir) + 1); XSTRING (dir)->data[0] = '~'; } if (insert_default_directory) insdef = dir; else insdef = build_string ("");#ifdef VMS count = specpdl_ptr - specpdl; specbind (intern ("completion-ignore-case"), Qt);#endif GCPRO2 (insdef, defalt); val = Fcompleting_read (prompt, intern ("read-file-name-internal"), dir, mustmatch, insert_default_directory ? insdef : Qnil);#ifdef VMS unbind_to (count);#endif UNGCPRO; if (NULL (val)) error ("No file name specified"); tem = Fstring_equal (val, insdef); if (!NULL (tem) && !NULL (defalt)) return defalt; return Fsubstitute_in_file_name (val);}syms_of_fileio (){ Qfile_error = intern ("file-error"); staticpro (&Qfile_error); Qfile_already_exists = intern("file-already-exists"); staticpro (&Qfile_already_exists); Fput (Qfile_error, Qerror_conditions, Fcons (Qfile_error, Fcons (Qerror, Qnil))); Fput (Qfile_error, Qerror_message, build_string ("File error")); Fput (Qfile_already_exists, Qerror_conditions, Fcons (Qfile_already_exists, Fcons (Qfile_error, Fcons (Qerror, Qnil)))); Fput (Qfile_already_exists, Qerror_message, build_string ("File already exists")); DEFVAR_BOOL ("insert-default-directory", &insert_default_directory, "*Non-nil means when reading a filename start with default dir in minibuffer."); insert_default_directory = 1; DEFVAR_BOOL ("vms-stmlf-recfm", &vms_stmlf_recfm, "*Non-nil means write new files with record format `stmlf'.\n\nil means use format `var'. This variable is meaningful only on VMS."); vms_stmlf_recfm = 0; defsubr (&Sfile_name_directory); defsubr (&Sfile_name_nondirectory); defsubr (&Sfile_name_as_directory); defsubr (&Sdirectory_file_name); defsubr (&Smake_temp_name); defsubr (&Sexpand_file_name); defsubr (&Ssubstitute_in_file_name); defsubr (&Scopy_file); defsubr (&Sdelete_file); defsubr (&Srename_file); defsubr (&Sadd_name_to_file);#ifdef S_IFLNK defsubr (&Smake_symbolic_link);#endif /* S_IFLNK */#ifdef VMS defsubr (&Sdefine_logical_name);#endif /* VMS */#ifdef HPUX_NET defsubr (&Ssysnetunam);#endif /* HPUX_NET */ defsubr (&Sfile_name_absolute_p); defsubr (&Sfile_exists_p); defsubr (&Sfile_readable_p); defsubr (&Sfile_writable_p); defsubr (&Sfile_symlink_p); defsubr (&Sfile_directory_p); defsubr (&Sfile_modes); defsubr (&Sset_file_modes); defsubr (&Sfile_newer_than_file_p); defsubr (&Sinsert_file_contents); defsubr (&Swrite_region); defsubr (&Sverify_visited_file_modtime); defsubr (&Sclear_visited_file_modtime); defsubr (&Sdo_auto_save); defsubr (&Sset_buffer_auto_saved); defsubr (&Srecent_auto_save_p); defsubr (&Sread_file_name_internal); defsubr (&Sread_file_name);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -