X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/8a7777fc1a5625685fab4ddbc5f6031ab591efb3..f5321b5c8a5fe2e79344f79f790283ae3a13c2a8:/src/fileio.c diff --git a/src/fileio.c b/src/fileio.c index 1635050466..aef7a01e0a 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -852,7 +852,12 @@ PREFIX should be an absolute file name.") /* Here we try to minimize useless stat'ing when this function is invoked many times successively with the same PREFIX. We achieve this by initializing count to a random value, and incrementing it - afterwards. */ + afterwards. + + We don't want make-temp-name to be called while dumping, + because then make_temp_name_count_initialized_p would get set + and then make_temp_name_count would not be set when Emacs starts. */ + if (!make_temp_name_count_initialized_p) { make_temp_name_count = (unsigned) time (NULL); @@ -930,6 +935,7 @@ See also the function `substitute-in-file-name'.") #ifdef DOS_NT int drive = 0; int collapse_newdir = 1; + int is_escaped = 0; #endif /* DOS_NT */ int length; Lisp_Object handler; @@ -973,7 +979,7 @@ See also the function `substitute-in-file-name'.") is needed at all) without requiring it to be expanded now. */ #ifdef DOS_NT /* Detect MSDOS file names with drive specifiers. */ - && ! (IS_DRIVE (o[0]) && (IS_DEVICE_SEP (o[1]) && IS_DIRECTORY_SEP (o[2]))) + && ! (IS_DRIVE (o[0]) && IS_DEVICE_SEP (o[1]) && IS_DIRECTORY_SEP (o[2])) #ifdef WINDOWSNT /* Detect Windows file names in UNC format. */ && ! (IS_DIRECTORY_SEP (o[0]) && IS_DIRECTORY_SEP (o[1])) @@ -1007,33 +1013,21 @@ See also the function `substitute-in-file-name'.") a local copy to modify, even if there ends up being no change. */ nm = strcpy (alloca (strlen (nm) + 1), nm); + /* Note if special escape prefix is present, but remove for now. */ + if (nm[0] == '/' && nm[1] == ':') + { + is_escaped = 1; + nm += 2; + } + /* Find and remove drive specifier if present; this makes nm absolute - even if the rest of the name appears to be relative. */ - { - unsigned char *colon = rindex (nm, ':'); - - if (colon) - /* Only recognize colon as part of drive specifier if there is a - single alphabetic character preceeding the colon (and if the - character before the drive letter, if present, is a directory - separator); this is to support the remote system syntax used by - ange-ftp, and the "po:username" syntax for POP mailboxes. */ - look_again: - if (nm == colon) - nm++; - else if (IS_DRIVE (colon[-1]) - && (colon == nm + 1 || IS_DIRECTORY_SEP (colon[-2]))) - { - drive = colon[-1]; - nm = colon + 1; - } - else - { - while (--colon >= nm) - if (colon[0] == ':') - goto look_again; - } - } + even if the rest of the name appears to be relative. Only look for + drive specifier at the beginning. */ + if (IS_DRIVE (nm[0]) && IS_DEVICE_SEP (nm[1])) + { + drive = nm[0]; + nm += 2; + } #ifdef WINDOWSNT /* If we see "c://somedir", we want to strip the first slash after the @@ -1058,10 +1052,10 @@ See also the function `substitute-in-file-name'.") if ( IS_DIRECTORY_SEP (nm[0]) #ifdef MSDOS - && drive + && drive && !is_escaped #endif #ifdef WINDOWSNT - && (drive || IS_DIRECTORY_SEP (nm[1])) + && (drive || IS_DIRECTORY_SEP (nm[1])) && !is_escaped #endif #ifdef VMS || index (nm, ':') @@ -1307,6 +1301,14 @@ See also the function `substitute-in-file-name'.") && !newdir) { newdir = XSTRING (default_directory)->data; +#ifdef DOS_NT + /* Note if special escape prefix is present, but remove for now. */ + if (newdir[0] == '/' && newdir[1] == ':') + { + is_escaped = 1; + newdir += 2; + } +#endif } #ifdef DOS_NT @@ -1382,9 +1384,9 @@ See also the function `substitute-in-file-name'.") if (newdir) { /* Get rid of any slash at the end of newdir, unless newdir is - just // (an incomplete UNC name). */ + just / or // (an incomplete UNC name). */ length = strlen (newdir); - if (length > 0 && IS_DIRECTORY_SEP (newdir[length - 1]) + if (length > 1 && IS_DIRECTORY_SEP (newdir[length - 1]) #ifdef WINDOWSNT && !(length == 2 && IS_DIRECTORY_SEP (newdir[0])) #endif @@ -1403,10 +1405,11 @@ See also the function `substitute-in-file-name'.") /* Now concatenate the directory and name to new space in the stack frame */ tlen += strlen (nm) + 1; #ifdef DOS_NT - /* Add reserved space for drive name. (The Microsoft x86 compiler + /* Reserve space for drive specifier and escape prefix, since either + or both may need to be inserted. (The Microsoft x86 compiler produces incorrect code if the following two lines are combined.) */ - target = (unsigned char *) alloca (tlen + 2); - target += 2; + target = (unsigned char *) alloca (tlen + 4); + target += 4; #else /* not DOS_NT */ target = (unsigned char *) alloca (tlen); #endif /* not DOS_NT */ @@ -1416,7 +1419,18 @@ See also the function `substitute-in-file-name'.") { #ifndef VMS if (nm[0] == 0 || IS_DIRECTORY_SEP (nm[0])) - strcpy (target, newdir); + { +#ifdef WINDOWSNT + /* If newdir is effectively "C:/", then the drive letter will have + been stripped and newdir will be "/". Concatenating with an + absolute directory in nm produces "//", which will then be + incorrectly treated as a network share. Ignore newdir in + this case (keeping the drive letter). */ + if (!(drive && nm[0] && IS_DIRECTORY_SEP (newdir[0]) + && newdir[1] == '\0')) +#endif + strcpy (target, newdir); + } else #endif file_name_as_directory (target, newdir); @@ -1525,6 +1539,13 @@ See also the function `substitute-in-file-name'.") target[0] = DRIVE_LETTER (drive); target[1] = ':'; } + /* Reinsert the escape prefix if required. */ + if (is_escaped) + { + target -= 2; + target[0] = '/'; + target[1] = ':'; + } CORRECT_DIR_SEPS (target); #endif /* DOS_NT */ @@ -2139,13 +2160,15 @@ barf_or_query_if_file_exists (absname, querystring, interactive, statptr, quick) struct stat *statptr; int quick; { - register Lisp_Object tem; + register Lisp_Object tem, encoded_filename; struct stat statbuf; struct gcpro gcpro1; + encoded_filename = ENCODE_FILE (absname); + /* stat is a good way to tell whether the file exists, regardless of what access permissions it has. */ - if (stat (XSTRING (absname)->data, &statbuf) >= 0) + if (stat (XSTRING (encoded_filename)->data, &statbuf) >= 0) { if (! interactive) Fsignal (Qfile_already_exists, @@ -3247,7 +3270,7 @@ This does code conversion according to the value of\n\ Lisp_Object p; int total; int not_regular = 0; - char read_buf[READ_BUF_SIZE]; + unsigned char read_buf[READ_BUF_SIZE]; struct coding_system coding; unsigned char buffer[1 << 14]; int replace_handled = 0; @@ -3356,25 +3379,39 @@ This does code conversion according to the value of\n\ /* Decide the coding-system of the file. */ { - Lisp_Object val = Qnil; + Lisp_Object val; + val = Qnil; if (!NILP (Vcoding_system_for_read)) val = Vcoding_system_for_read; - else + else if (! NILP (replace)) + /* In REPLACE mode, we can use the same coding system + that was used to visit the file. */ + val = current_buffer->buffer_file_coding_system; + else if (! not_regular) { + /* Don't try looking inside a file for a coding system specification + if it is not seekable. */ if (! NILP (Vset_auto_coding_function)) { /* Find a coding system specified in the heading two lines or in the tailing several lines of the file. We assume that the 1K-byte and 3K-byte for heading and tailing respectively are sufficient fot this purpose. */ - int how_many, nread; + int nread; + int beginning_of_end, end_of_beginning; if (st.st_size <= (1024 * 4)) - nread = read (fd, read_buf, 1024 * 4); + { + nread = read (fd, read_buf, 1024 * 4); + end_of_beginning = nread; + beginning_of_end = 0; + } else { nread = read (fd, read_buf, 1024); + end_of_beginning = nread; + beginning_of_end = nread; if (nread >= 0) { if (lseek (fd, st.st_size - (1024 * 3), 0) < 0) @@ -3383,17 +3420,83 @@ This does code conversion according to the value of\n\ nread += read (fd, read_buf + nread, 1024 * 3); } } - + if (nread < 0) error ("IO error reading %s: %s", XSTRING (orig_filename)->data, strerror (errno)); else if (nread > 0) { + int i; + int possible_spec = 0; + unsigned char *p, *p1; Lisp_Object tem; - /* Always make this a unibyte string - because we have not yet decoded it. */ - tem = make_unibyte_string (read_buf, nread); - val = call1 (Vset_auto_coding_function, tem); + unsigned char *copy = (unsigned char *) alloca (nread + 1); + + /* Make a copy of the contents of read_buf in COPY, + and convert it to lower case so we can compare + more efficiently. */ + bcopy (read_buf, copy, nread); + for (i = 0; i < nread; i++) + copy[i] = DOWNCASE (copy[i]); + /* Ensure various comparisons fail at end of data. */ + copy[nread] = 0; + + /* Now test quickly whether the file contains a -*- line. */ + p = copy; + while (*p != '\n' && p - copy < end_of_beginning) + p++; + if (copy[0] == '#' && copy[1] == '!') + while (*p != '\n' && p - copy < end_of_beginning) + p++; + p1 = copy; + while (p - p1 >= 3) + { + if (p1[0] == '-' && p1[1] == '*' && p1[2] == '-') + { + while (p - p1 >= 7) + { + if (! bcmp ("coding:", p1, 7)) + { + possible_spec = 1; + goto win; + } + p1++; + } + break; + } + p1++; + } + + /* Test quickly whether the file + contains a local variables list. */ + p = ©[nread - 1]; + p1 = ©[beginning_of_end]; + while (p > p1) + { + if (p[0] == '\n' && p[1] == '\f') + break; + p--; + } + p1 = ©[nread]; + while (p1 - p >= 16) + { + if (! bcmp ("local variables:", p, 16)) + { + possible_spec = 1; + break; + } + p++; + } + win: + + if (possible_spec) + { + /* Always make this a unibyte string + because we have not yet decoded it. */ + tem = make_unibyte_string (read_buf, nread); + val = call1 (Vset_auto_coding_function, tem); + } + /* Rewind the file for the actual read done later. */ if (lseek (fd, 0, 0) < 0) report_file_error ("Setting file position", @@ -3404,10 +3507,11 @@ This does code conversion according to the value of\n\ { Lisp_Object args[6], coding_systems; - args[0] = Qinsert_file_contents, args[1] = orig_filename, - args[2] = visit, args[3] = beg, args[4] = end, args[5] = replace; + args[0] = Qinsert_file_contents, args[1] = orig_filename; + args[2] = visit, args[3] = beg, args[4] = end, args[5] = replace; coding_systems = Ffind_operation_coding_system (6, args); - if (CONSP (coding_systems)) val = XCONS (coding_systems)->car; + if (CONSP (coding_systems)) + val = XCONS (coding_systems)->car; } } @@ -3441,7 +3545,9 @@ This does code conversion according to the value of\n\ But if we discover the need for conversion, we give up on this method and let the following if-statement handle the replace job. */ if (!NILP (replace) - && ! CODING_REQUIRE_DECODING (&coding)) + && ! CODING_REQUIRE_DECODING (&coding) + && (coding.eol_type == CODING_EOL_UNDECIDED + || coding.eol_type == CODING_EOL_LF)) { /* same_at_start and same_at_end count bytes, because file access counts bytes @@ -3757,7 +3863,14 @@ This does code conversion according to the value of\n\ we are taking from the file. */ inserted -= (Z_BYTE - same_at_end) + (same_at_start - BEG_BYTE); del_range_byte (same_at_start, same_at_end, 0); - SET_PT_BOTH (GPT, GPT_BYTE); + if (same_at_end != same_at_start) + SET_PT_BOTH (GPT, GPT_BYTE); + else + { + /* Insert from the file at the proper position. */ + temp = BYTE_TO_CHAR (same_at_start); + SET_PT_BOTH (temp, same_at_start); + } insert_1 (conversion_buffer + same_at_start - BEG_BYTE, inserted, 0, 0, 0); @@ -3893,11 +4006,12 @@ This does code conversion according to the value of\n\ /* Use the conversion type to determine buffer-file-type (find-buffer-file-type is now used to help determine the conversion). */ - if (coding.eol_type != CODING_EOL_UNDECIDED - && coding.eol_type != CODING_EOL_LF) - current_buffer->buffer_file_type = Qnil; - else + if ((coding.eol_type == CODING_EOL_UNDECIDED + || coding.eol_type == CODING_EOL_LF) + && ! CODING_REQUIRE_DECODING (&coding)) current_buffer->buffer_file_type = Qt; + else + current_buffer->buffer_file_type = Qnil; #endif }