Partially sync files.el from XEmacs 21.5 for wildcard support.
[sxemacs] / src / fileio.c
index 63b1959..4a15934 100644 (file)
@@ -35,6 +35,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 #ifdef FILE_CODING
 #include "mule/file-coding.h"
 #endif
+#include "ent/ent.h"
 
 #ifdef HAVE_LIBGEN_H           /* Must come before sysfile.h */
 #include <libgen.h>
@@ -448,7 +449,7 @@ Bytecount file_basename_match_extension(Lisp_Object filename,
        Bytecount match = -1;
        Bytecount len = XSTRING_LENGTH( extension );
        if ( len > 0 ) {
-               char     re[len+6], 
+               char     re[len+6],
                        *rep = re;
                Bufbyte *ext = XSTRING_DATA(extension);
                Lisp_Object regexp;
@@ -465,7 +466,7 @@ Bytecount file_basename_match_extension(Lisp_Object filename,
                   terminator if need to append...
                */
                rep += len-1;
-               if ( *rep++ != '$' ) 
+               if ( *rep++ != '$' )
                        *rep++ = '$';
                *rep = '\0';
                regexp = make_string( (Bufbyte*)re, strlen(re));
@@ -519,7 +520,7 @@ It ignores trailing slash.
        res = make_string(p, end - p);
        if ( STRINGP( extension ) ) {
                Bytecount match;
-               match = file_basename_match_extension(res, 
+               match = file_basename_match_extension(res,
                                                      extension);
                if ( match >= 0 )
                        RETURN_UNGCPRO(make_string(p, match));
@@ -528,7 +529,7 @@ It ignores trailing slash.
                do {
                        ext = XCAR(rest);
                        Bytecount match;
-                       match = file_basename_match_extension(res, 
+                       match = file_basename_match_extension(res,
                                                              ext);
                        if ( match >= 0 )
                                RETURN_UNGCPRO(make_string(p, match));
@@ -601,17 +602,18 @@ get a current directory to run processes in.
        return Ffile_name_directory(filename);
 }
 \f
-static char *file_name_as_directory(char *out, char *in)
+static char *file_name_as_directory(char *out, const char *in, size_t len)
 {
        /* This function cannot GC */
        int size = strlen(in);
 
        if (size == 0) {
+               assert(len >= 3);
                out[0] = '.';
                out[1] = DIRECTORY_SEP;
                out[2] = '\0';
        } else {
-               strcpy(out, in);
+               xstrncpy(out, in, len);
                /* Append a slash if necessary */
                if (!IS_ANY_SEP(out[size - 1])) {
                        out[size] = DIRECTORY_SEP;
@@ -633,8 +635,9 @@ except for (file-name-as-directory \"\") => \"./\".
       (filename))
 {
        /* This function can GC.  GC checked 2000-07-28 ben */
-       char *buf;
-       Lisp_Object handler;
+       size_t len = 0;
+       char *buf = NULL;
+       Lisp_Object handler = Qnil;
 
        CHECK_STRING(filename);
 
@@ -645,9 +648,10 @@ except for (file-name-as-directory \"\") => \"./\".
                return call2_check_string(handler, Qfile_name_as_directory,
                                          filename);
 
-       buf = (char *)alloca(XSTRING_LENGTH(filename) + 10);
+       len = XSTRING_LENGTH(filename) + 10;
+       buf = (char *)alloca(len);
        return build_string(file_name_as_directory
-                           (buf, (char *)XSTRING_DATA(filename)));
+                           (buf, (char*)XSTRING_DATA(filename), len));
 }
 \f
 /*
@@ -657,13 +661,13 @@ except for (file-name-as-directory \"\") => \"./\".
  * Value is nonzero if the string output is different from the input.
  */
 
-static int directory_file_name(const char *src, char *dst)
+static int directory_file_name(const char *src, char *dst, size_t len)
 {
        /* This function cannot GC */
        long slen = strlen(src);
        /* Process as Unix format: just remove any final slash.
           But leave "/" unchanged; do not change it to "".  */
-       strcpy(dst, src);
+       xstrncpy(dst, src, len);
        if (slen > 1 && IS_DIRECTORY_SEP(dst[slen - 1])
            )
                dst[slen - 1] = 0;
@@ -680,7 +684,8 @@ In Unix-syntax, this function just removes the final slash.
       (directory))
 {
        /* This function can GC.  GC checked 2000-07-28 ben */
-       char *buf;
+       size_t len = 0;
+       char *buf = NULL;
        Lisp_Object handler;
 
        CHECK_STRING(directory);
@@ -696,8 +701,9 @@ In Unix-syntax, this function just removes the final slash.
        if (!NILP(handler))
                return call2_check_string(handler, Qdirectory_file_name,
                                          directory);
-       buf = (char *)alloca(XSTRING_LENGTH(directory) + 20);
-       directory_file_name((char *)XSTRING_DATA(directory), buf);
+       len = XSTRING_LENGTH(directory) + 20;
+       buf = (char *)alloca(len);
+       directory_file_name((char *)XSTRING_DATA(directory), buf, len);
        return build_string(buf);
 }
 \f
@@ -1024,12 +1030,12 @@ See also the function `substitute-in-file-name'.
 
        if (newdir) {
                if (nm[0] == 0 || IS_DIRECTORY_SEP(nm[0]))
-                       strcpy((char *)target, (char *)newdir);
+                       xstrncpy((char *)target, (char *)newdir, tlen);
                else
-                       file_name_as_directory((char *)target, (char *)newdir);
+                       file_name_as_directory((char *)target, (char *)newdir, tlen);
        }
 
-       strcat((char *)target, (char *)nm);
+       xstrncat((char *)target, (char *)nm, tlen-1);
 
        /* ASSERT (IS_DIRECTORY_SEP (target[0])) if not VMS */
 
@@ -1093,7 +1099,7 @@ in the realpath() function.
        {
                Lisp_Object handler =
                        Ffind_file_name_handler(expanded_name, Qfile_truename);
-               
+
                if (!NILP(handler))
                        RETURN_UNGCPRO
                                (call2_check_string
@@ -1114,11 +1120,11 @@ in the realpath() function.
                        goto toolong;
 
                /* Try doing it all at once. */
-               /* !! Does realpath() Mule-encapsulate?  Answer: Nope! 
+               /* !! Does realpath() Mule-encapsulate?  Answer: Nope!
                   So we do it above */
                if (path != NULL && !xrealpath((char *)path, resolved_path)) {
                        /* Didn't resolve it -- have to do it one
-                          component at a time. 
+                          component at a time.
 
                           "realpath" is a typically useless, stupid
                           un*x piece of crap.  It claims to return a
@@ -1141,7 +1147,7 @@ in the realpath() function.
 
                           Since we depend on undocumented semantics
                           of various system realpath()s, we just use
-                          our own version in realpath.c. 
+                          our own version in realpath.c.
                        */
                        for (;;) {
                                Extbyte *pos = NULL;
@@ -1160,7 +1166,7 @@ in the realpath() function.
                                                *p = DIRECTORY_SEP;
                                        else
                                                break;
-                                       
+
                                } else if (errno == ENOENT || errno == EACCES) {
                                        /* Failed on this component.
                                           Just tack on the rest of
@@ -1174,13 +1180,13 @@ in the realpath() function.
                                           places in resolved_path the
                                           absolute pathname of the
                                           path component which could
-                                          not be resolved." 
+                                          not be resolved."
                                        */
                                        if (p == NULL ) {
                                                break;
                                        }
                                        int plen = elen - (p - path);
-                                       
+
                                        if (rlen > 1 &&
                                            IS_DIRECTORY_SEP
                                            (resolved_path[rlen - 1]))
@@ -1203,10 +1209,10 @@ in the realpath() function.
                        Lisp_Object resolved_name;
                        int rlen = strlen(resolved_path);
 
-                       if (elen > 0 
+                       if (elen > 0
                            && IS_DIRECTORY_SEP(
-                                   XSTRING_BYTE(expanded_name, elen-1)) 
-                           && !(rlen > 0 && 
+                                   XSTRING_BYTE(expanded_name, elen-1))
+                           && !(rlen > 0 &&
                                 IS_DIRECTORY_SEP(resolved_path[rlen-1]))) {
                                if (rlen + 1 > countof(resolved_path))
                                        goto toolong;
@@ -1245,6 +1251,7 @@ If `/~' appears, all of FILENAME through that `/' is discarded.
        Bufbyte *target = 0;
        int total = 0;
        int substituted = 0;
+       size_t avail = 0;
        Bufbyte *xnm;
        Lisp_Object handler;
 
@@ -1321,19 +1328,22 @@ If `/~' appears, all of FILENAME through that `/' is discarded.
 
        /* If substitution required, recopy the filename and do it */
        /* Make space in stack frame for the new copy */
-       xnm = (Bufbyte *) alloca(XSTRING_LENGTH(filename) + total + 1);
+       avail = XSTRING_LENGTH(filename) + total + 1;
+       xnm = (Bufbyte *) alloca(avail);
        x = xnm;
 
        /* Copy the rest of the name through, replacing $ constructs with values */
        for (p = nm; *p;)
-               if (*p != '$')
+               if (*p != '$') {
                        *x++ = *p++;
-               else {
+                       avail--;
+               } else {
                        p++;
                        if (p == endp)
                                goto badsubst;
                        else if (*p == '$') {
                                *x++ = *p++;
+                               avail--;
                                continue;
                        } else if (*p == '{') {
                                o = ++p;
@@ -1359,8 +1369,9 @@ If `/~' appears, all of FILENAME through that `/' is discarded.
                        if (!o)
                                goto badvar;
 
-                       strcpy((char *)x, (char *)o);
+                       xstrncpy((char *)x, (char *)o, avail);
                        x += strlen((char *)o);
+                       avail -= strlen((char *)o);
                }
 
        *x = 0;
@@ -1534,6 +1545,7 @@ A prefix arg makes KEEP-TIME non-nil.
                                 O_RDONLY | OPEN_BINARY, 0);
        if (ifd < 0) {
                report_file_error("Opening input file", list1(filename));
+               goto end;
        }
        record_unwind_protect(close_file_unwind, make_int(ifd));
 
@@ -1580,6 +1592,8 @@ A prefix arg makes KEEP-TIME non-nil.
                                report_file_error("I/O error", list1(newname));
                }
 
+               if(close(ifd) <0)
+                       report_file_error("I/O error", list1(filename));
                /* Closing the output clobbers the file times on some systems.  */
                if (close(ofd) < 0)
                        report_file_error("I/O error", list1(newname));
@@ -1604,6 +1618,7 @@ A prefix arg makes KEEP-TIME non-nil.
                unbind_to(speccount, Qnil);
        }
 
+end:
        UNGCPRO;
        return Qnil;
 }
@@ -1636,9 +1651,9 @@ Create a directory.  One argument, a file name string.
        }
        strncpy(dir, (char *)XSTRING_DATA(dirname_),
                XSTRING_LENGTH(dirname_) + 1);
-        dir[XSTRING_LENGTH(dirname_)]='\0';
+       dir[XSTRING_LENGTH(dirname_)]='\0';
        if (dir[XSTRING_LENGTH(dirname_) - 1] == '/')
-                dir[XSTRING_LENGTH(dirname_) - 1] = '\0';
+               dir[XSTRING_LENGTH(dirname_) - 1] = '\0';
 
        if (mkdir(dir, 0777) != 0)
                report_file_error("Creating directory", list1(dirname_));
@@ -3068,13 +3083,13 @@ here because write-region handler writers need to be aware of it.
           to avoid a "file has changed on disk" warning on
           next attempt to save.  */
        if (visiting)
-           if (stat_res == 0)
+          if (stat_res == 0)
                current_buffer->modtime = st.st_mtime;
-          /* else: 
+          /* else:
                If sxemacs_stat failed, we have bigger problems, and
                   most likely the file is gone, so the error next time is
                   the right behavior
-            */
+           */
 
        if (failure) {
                errno = save_errno;
@@ -3714,6 +3729,9 @@ Non-nil second argument means save only current buffer.
        if (listdesc < 0 && !auto_saved && STRINGP(listfile))
                unlink((char *)XSTRING_DATA(listfile));
 
+       if (listdesc >= 0)
+               close(listdesc);
+
        /* Show "...done" only if the echo area would otherwise be empty. */
        if (auto_saved && NILP(no_message)
            && NILP(clear_echo_area(selected_frame(), Qauto_saving, 0))) {