(Fexpand_file_name) [WINDOWSNT]: Be careful not to
[bpt/emacs.git] / src / fileio.c
index 046ac72..aef7a01 100644 (file)
@@ -1419,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);
@@ -3259,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;
@@ -3368,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)
@@ -3395,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 = &copy[nread - 1];
+               p1 = &copy[beginning_of_end];
+               while (p > p1)
+                 {
+                   if (p[0] == '\n' && p[1] == '\f')
+                     break;
+                   p--;
+                 }
+               p1 = &copy[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",
@@ -3416,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;
          }
       }
 
@@ -3453,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
@@ -3912,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
     }