1*60165Shibler /* File IO for GNU Emacs. 2*60165Shibler Copyright (C) 1985, 1986, 1987, 1988, 1990 Free Software Foundation, Inc. 3*60165Shibler 4*60165Shibler This file is part of GNU Emacs. 5*60165Shibler 6*60165Shibler GNU Emacs is free software; you can redistribute it and/or modify 7*60165Shibler it under the terms of the GNU General Public License as published by 8*60165Shibler the Free Software Foundation; either version 1, or (at your option) 9*60165Shibler any later version. 10*60165Shibler 11*60165Shibler GNU Emacs is distributed in the hope that it will be useful, 12*60165Shibler but WITHOUT ANY WARRANTY; without even the implied warranty of 13*60165Shibler MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*60165Shibler GNU General Public License for more details. 15*60165Shibler 16*60165Shibler You should have received a copy of the GNU General Public License 17*60165Shibler along with GNU Emacs; see the file COPYING. If not, write to 18*60165Shibler the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ 19*60165Shibler 20*60165Shibler 21*60165Shibler #include <sys/types.h> 22*60165Shibler #ifdef hpux 23*60165Shibler /* needed by <pwd.h> */ 24*60165Shibler #include <stdio.h> 25*60165Shibler #undef NULL 26*60165Shibler #endif 27*60165Shibler #include <sys/stat.h> 28*60165Shibler #include <pwd.h> 29*60165Shibler #include <ctype.h> 30*60165Shibler #include <sys/dir.h> 31*60165Shibler #include <errno.h> 32*60165Shibler 33*60165Shibler #ifndef VMS 34*60165Shibler extern int errno; 35*60165Shibler extern char *sys_errlist[]; 36*60165Shibler extern int sys_nerr; 37*60165Shibler #endif 38*60165Shibler 39*60165Shibler #define err_str(a) ((a) < sys_nerr ? sys_errlist[a] : "unknown error") 40*60165Shibler 41*60165Shibler #ifdef APOLLO 42*60165Shibler #include <sys/time.h> 43*60165Shibler #endif 44*60165Shibler 45*60165Shibler #ifdef NULL 46*60165Shibler #undef NULL 47*60165Shibler #endif 48*60165Shibler #include "config.h" 49*60165Shibler #include "lisp.h" 50*60165Shibler #include "buffer.h" 51*60165Shibler #include "window.h" 52*60165Shibler 53*60165Shibler #ifdef VMS 54*60165Shibler #include <perror.h> 55*60165Shibler #include <file.h> 56*60165Shibler #include <rmsdef.h> 57*60165Shibler #include <fab.h> 58*60165Shibler #include <nam.h> 59*60165Shibler #endif 60*60165Shibler 61*60165Shibler #ifdef HAVE_TIMEVAL 62*60165Shibler #ifdef HPUX 63*60165Shibler #include <time.h> 64*60165Shibler #else 65*60165Shibler #include <sys/time.h> 66*60165Shibler #endif 67*60165Shibler #endif 68*60165Shibler 69*60165Shibler #ifdef HPUX 70*60165Shibler #include <netio.h> 71*60165Shibler #include <errnet.h> 72*60165Shibler #endif 73*60165Shibler 74*60165Shibler #ifndef O_WRONLY 75*60165Shibler #define O_WRONLY 1 76*60165Shibler #endif 77*60165Shibler 78*60165Shibler #define min(a, b) ((a) < (b) ? (a) : (b)) 79*60165Shibler #define max(a, b) ((a) > (b) ? (a) : (b)) 80*60165Shibler 81*60165Shibler /* Nonzero during writing of auto-save files */ 82*60165Shibler int auto_saving; 83*60165Shibler 84*60165Shibler /* Nonzero means, when reading a filename in the minibuffer, 85*60165Shibler start out by inserting the default directory into the minibuffer. */ 86*60165Shibler int insert_default_directory; 87*60165Shibler 88*60165Shibler /* On VMS, nonzero means write new files with record format stmlf. 89*60165Shibler Zero means use var format. */ 90*60165Shibler int vms_stmlf_recfm; 91*60165Shibler 92*60165Shibler Lisp_Object Qfile_error, Qfile_already_exists; 93*60165Shibler 94*60165Shibler report_file_error (string, data) 95*60165Shibler char *string; 96*60165Shibler Lisp_Object data; 97*60165Shibler { 98*60165Shibler Lisp_Object errstring; 99*60165Shibler 100*60165Shibler if (errno >= 0 && errno < sys_nerr) 101*60165Shibler errstring = build_string (sys_errlist[errno]); 102*60165Shibler else 103*60165Shibler errstring = build_string ("undocumented error code"); 104*60165Shibler 105*60165Shibler /* System error messages are capitalized. Downcase the initial. */ 106*60165Shibler XSTRING (errstring)->data[0] = DOWNCASE (XSTRING (errstring)->data[0]); 107*60165Shibler 108*60165Shibler while (1) 109*60165Shibler Fsignal (Qfile_error, 110*60165Shibler Fcons (build_string (string), Fcons (errstring, data))); 111*60165Shibler } 112*60165Shibler 113*60165Shibler DEFUN ("file-name-directory", Ffile_name_directory, Sfile_name_directory, 114*60165Shibler 1, 1, 0, 115*60165Shibler "Return the directory component in file name NAME.\n\ 116*60165Shibler Return nil if NAME does not include a directory.\n\ 117*60165Shibler Otherwise returns a directory spec.\n\ 118*60165Shibler Given a Unix syntax file name, returns a string ending in slash;\n\ 119*60165Shibler on VMS, perhaps instead a string ending in :, ] or >.") 120*60165Shibler (file) 121*60165Shibler Lisp_Object file; 122*60165Shibler { 123*60165Shibler register unsigned char *beg; 124*60165Shibler register unsigned char *p; 125*60165Shibler 126*60165Shibler CHECK_STRING (file, 0); 127*60165Shibler 128*60165Shibler beg = XSTRING (file)->data; 129*60165Shibler p = beg + XSTRING (file)->size; 130*60165Shibler 131*60165Shibler while (p != beg && p[-1] != '/' 132*60165Shibler #ifdef VMS 133*60165Shibler && p[-1] != ':' && p[-1] != ']' && p[-1] != '>' 134*60165Shibler #endif /* VMS */ 135*60165Shibler ) p--; 136*60165Shibler 137*60165Shibler if (p == beg) 138*60165Shibler return Qnil; 139*60165Shibler return make_string (beg, p - beg); 140*60165Shibler } 141*60165Shibler 142*60165Shibler DEFUN ("file-name-nondirectory", Ffile_name_nondirectory, Sfile_name_nondirectory, 143*60165Shibler 1, 1, 0, 144*60165Shibler "Return file name NAME sans its directory.\n\ 145*60165Shibler For example, in a Unix-syntax file name,\n\ 146*60165Shibler this is everything after the last slash,\n\ 147*60165Shibler or the entire name if it contains no slash.") 148*60165Shibler (file) 149*60165Shibler Lisp_Object file; 150*60165Shibler { 151*60165Shibler register unsigned char *beg, *p, *end; 152*60165Shibler 153*60165Shibler CHECK_STRING (file, 0); 154*60165Shibler 155*60165Shibler beg = XSTRING (file)->data; 156*60165Shibler end = p = beg + XSTRING (file)->size; 157*60165Shibler 158*60165Shibler while (p != beg && p[-1] != '/' 159*60165Shibler #ifdef VMS 160*60165Shibler && p[-1] != ':' && p[-1] != ']' && p[-1] != '>' 161*60165Shibler #endif /* VMS */ 162*60165Shibler ) p--; 163*60165Shibler 164*60165Shibler return make_string (p, end - p); 165*60165Shibler } 166*60165Shibler 167*60165Shibler char * 168*60165Shibler file_name_as_directory (out, in) 169*60165Shibler char *out, *in; 170*60165Shibler { 171*60165Shibler int size = strlen (in) - 1; 172*60165Shibler 173*60165Shibler strcpy (out, in); 174*60165Shibler 175*60165Shibler #ifdef VMS 176*60165Shibler /* Is it already a directory string? */ 177*60165Shibler if (in[size] == ':' || in[size] == ']' || in[size] == '>') 178*60165Shibler return out; 179*60165Shibler /* Is it a VMS directory file name? If so, hack VMS syntax. */ 180*60165Shibler else if (! index (in, '/') 181*60165Shibler && ((size > 3 && ! strcmp (&in[size - 3], ".DIR")) 182*60165Shibler || (size > 3 && ! strcmp (&in[size - 3], ".dir")) 183*60165Shibler || (size > 5 && (! strncmp (&in[size - 5], ".DIR", 4) 184*60165Shibler || ! strncmp (&in[size - 5], ".dir", 4)) 185*60165Shibler && (in[size - 1] == '.' || in[size - 1] == ';') 186*60165Shibler && in[size] == '1'))) 187*60165Shibler { 188*60165Shibler register char *p, *dot; 189*60165Shibler char brack; 190*60165Shibler 191*60165Shibler /* x.dir -> [.x] 192*60165Shibler dir:x.dir --> dir:[x] 193*60165Shibler dir:[x]y.dir --> dir:[x.y] */ 194*60165Shibler p = in + size; 195*60165Shibler while (p != in && *p != ':' && *p != '>' && *p != ']') p--; 196*60165Shibler if (p != in) 197*60165Shibler { 198*60165Shibler strncpy (out, in, p - in); 199*60165Shibler out[p - in] = '\0'; 200*60165Shibler if (*p == ':') 201*60165Shibler { 202*60165Shibler brack = ']'; 203*60165Shibler strcat (out, ":["); 204*60165Shibler } 205*60165Shibler else 206*60165Shibler { 207*60165Shibler brack = *p; 208*60165Shibler strcat (out, "."); 209*60165Shibler } 210*60165Shibler p++; 211*60165Shibler } 212*60165Shibler else 213*60165Shibler { 214*60165Shibler brack = ']'; 215*60165Shibler strcpy (out, "[."); 216*60165Shibler } 217*60165Shibler if (dot = index (p, '.')) 218*60165Shibler { 219*60165Shibler /* blindly remove any extension */ 220*60165Shibler size = strlen (out) + (dot - p); 221*60165Shibler strncat (out, p, dot - p); 222*60165Shibler } 223*60165Shibler else 224*60165Shibler { 225*60165Shibler strcat (out, p); 226*60165Shibler size = strlen (out); 227*60165Shibler } 228*60165Shibler out[size++] = brack; 229*60165Shibler out[size] = '\0'; 230*60165Shibler } 231*60165Shibler #else /* not VMS */ 232*60165Shibler /* For Unix syntax, Append a slash if necessary */ 233*60165Shibler if (out[size] != '/') 234*60165Shibler strcat (out, "/"); 235*60165Shibler #endif /* not VMS */ 236*60165Shibler return out; 237*60165Shibler } 238*60165Shibler 239*60165Shibler DEFUN ("file-name-as-directory", Ffile_name_as_directory, 240*60165Shibler Sfile_name_as_directory, 1, 1, 0, 241*60165Shibler "Return a string representing file FILENAME interpreted as a directory.\n\ 242*60165Shibler This string can be used as the value of default-directory\n\ 243*60165Shibler or passed as second argument to expand-file-name.\n\ 244*60165Shibler For a Unix-syntax file name, just appends a slash.\n\ 245*60165Shibler On VMS, converts \"[X]FOO.DIR\" to \"[X.FOO]\", etc.") 246*60165Shibler (file) 247*60165Shibler Lisp_Object file; 248*60165Shibler { 249*60165Shibler char *buf; 250*60165Shibler 251*60165Shibler CHECK_STRING (file, 0); 252*60165Shibler if (NULL (file)) 253*60165Shibler return Qnil; 254*60165Shibler buf = (char *) alloca (XSTRING (file)->size + 10); 255*60165Shibler return build_string (file_name_as_directory (buf, XSTRING (file)->data)); 256*60165Shibler } 257*60165Shibler 258*60165Shibler /* 259*60165Shibler * Convert from directory name to filename. 260*60165Shibler * On VMS: 261*60165Shibler * xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1 262*60165Shibler * xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1 263*60165Shibler * On UNIX, it's simple: just make sure there is a terminating / 264*60165Shibler 265*60165Shibler * Value is nonzero if the string output is different from the input. 266*60165Shibler */ 267*60165Shibler 268*60165Shibler directory_file_name (src, dst) 269*60165Shibler char *src, *dst; 270*60165Shibler { 271*60165Shibler long slen; 272*60165Shibler #ifdef VMS 273*60165Shibler long rlen; 274*60165Shibler char * ptr, * rptr; 275*60165Shibler char bracket; 276*60165Shibler struct FAB fab = cc$rms_fab; 277*60165Shibler struct NAM nam = cc$rms_nam; 278*60165Shibler char esa[NAM$C_MAXRSS]; 279*60165Shibler #endif /* VMS */ 280*60165Shibler 281*60165Shibler slen = strlen (src) - 1; 282*60165Shibler #ifdef VMS 283*60165Shibler if (! index (src, '/') 284*60165Shibler && (src[slen] == ']' || src[slen] == ':' || src[slen] == '>')) 285*60165Shibler { 286*60165Shibler /* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */ 287*60165Shibler fab.fab$l_fna = src; 288*60165Shibler fab.fab$b_fns = slen + 1; 289*60165Shibler fab.fab$l_nam = &nam; 290*60165Shibler fab.fab$l_fop = FAB$M_NAM; 291*60165Shibler 292*60165Shibler nam.nam$l_esa = esa; 293*60165Shibler nam.nam$b_ess = sizeof esa; 294*60165Shibler nam.nam$b_nop |= NAM$M_SYNCHK; 295*60165Shibler 296*60165Shibler /* We call SYS$PARSE to handle such things as [--] for us. */ 297*60165Shibler if (SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL) 298*60165Shibler { 299*60165Shibler slen = nam.nam$b_esl - 1; 300*60165Shibler if (esa[slen] == ';' && esa[slen - 1] == '.') 301*60165Shibler slen -= 2; 302*60165Shibler esa[slen + 1] = '\0'; 303*60165Shibler src = esa; 304*60165Shibler } 305*60165Shibler if (src[slen] != ']' && src[slen] != '>') 306*60165Shibler { 307*60165Shibler /* what about when we have logical_name:???? */ 308*60165Shibler if (src[slen] == ':') 309*60165Shibler { /* Xlate logical name and see what we get */ 310*60165Shibler ptr = strcpy (dst, src); /* upper case for getenv */ 311*60165Shibler while (*ptr) 312*60165Shibler { 313*60165Shibler if ('a' <= *ptr && *ptr <= 'z') 314*60165Shibler *ptr -= 040; 315*60165Shibler ptr++; 316*60165Shibler } 317*60165Shibler dst[slen] = 0; /* remove colon */ 318*60165Shibler if (!(src = egetenv (dst))) 319*60165Shibler return 0; 320*60165Shibler /* should we jump to the beginning of this procedure? 321*60165Shibler Good points: allows us to use logical names that xlate 322*60165Shibler to Unix names, 323*60165Shibler Bad points: can be a problem if we just translated to a device 324*60165Shibler name... 325*60165Shibler For now, I'll punt and always expect VMS names, and hope for 326*60165Shibler the best! */ 327*60165Shibler slen = strlen (src) - 1; 328*60165Shibler if (src[slen] != ']' && src[slen] != '>') 329*60165Shibler { /* no recursion here! */ 330*60165Shibler strcpy (dst, src); 331*60165Shibler return 0; 332*60165Shibler } 333*60165Shibler } 334*60165Shibler else 335*60165Shibler { /* not a directory spec */ 336*60165Shibler strcpy (dst, src); 337*60165Shibler return 0; 338*60165Shibler } 339*60165Shibler } 340*60165Shibler bracket = src[slen]; 341*60165Shibler if (!(ptr = index (src, bracket - 2))) 342*60165Shibler { /* no opening bracket */ 343*60165Shibler strcpy (dst, src); 344*60165Shibler return 0; 345*60165Shibler } 346*60165Shibler if (!(rptr = rindex (src, '.'))) 347*60165Shibler rptr = ptr; 348*60165Shibler slen = rptr - src; 349*60165Shibler strncpy (dst, src, slen); 350*60165Shibler dst[slen] = '\0'; 351*60165Shibler if (*rptr == '.') 352*60165Shibler { 353*60165Shibler dst[slen++] = bracket; 354*60165Shibler dst[slen] = '\0'; 355*60165Shibler } 356*60165Shibler else 357*60165Shibler { 358*60165Shibler /* If we have the top-level of a rooted directory (i.e. xx:[000000]), 359*60165Shibler then translate the device and recurse. */ 360*60165Shibler if (dst[slen - 1] == ':' 361*60165Shibler && dst[slen - 2] != ':' /* skip decnet nodes */ 362*60165Shibler && strcmp(src + slen, "[000000]") == 0) 363*60165Shibler { 364*60165Shibler dst[slen - 1] = '\0'; 365*60165Shibler if ((ptr = egetenv (dst)) 366*60165Shibler && (rlen = strlen (ptr) - 1) > 0 367*60165Shibler && (ptr[rlen] == ']' || ptr[rlen] == '>') 368*60165Shibler && ptr[rlen - 1] == '.') 369*60165Shibler { 370*60165Shibler ptr[rlen - 1] = ']'; 371*60165Shibler ptr[rlen] = '\0'; 372*60165Shibler return directory_file_name (ptr, dst); 373*60165Shibler } 374*60165Shibler else 375*60165Shibler dst[slen - 1] = ':'; 376*60165Shibler } 377*60165Shibler strcat (dst, "[000000]"); 378*60165Shibler slen += 8; 379*60165Shibler } 380*60165Shibler rptr++; 381*60165Shibler rlen = strlen (rptr) - 1; 382*60165Shibler strncat (dst, rptr, rlen); 383*60165Shibler dst[slen + rlen] = '\0'; 384*60165Shibler strcat (dst, ".DIR.1"); 385*60165Shibler return 1; 386*60165Shibler } 387*60165Shibler #endif /* VMS */ 388*60165Shibler /* Process as Unix format: just remove any final slash. 389*60165Shibler But leave "/" unchanged; do not change it to "". */ 390*60165Shibler strcpy (dst, src); 391*60165Shibler if (dst[slen] == '/' && slen > 1) 392*60165Shibler dst[slen] = 0; 393*60165Shibler return 1; 394*60165Shibler } 395*60165Shibler 396*60165Shibler DEFUN ("directory-file-name", Fdirectory_file_name, Sdirectory_file_name, 397*60165Shibler 1, 1, 0, 398*60165Shibler "Returns the file name of the directory named DIR.\n\ 399*60165Shibler This is the name of the file that holds the data for the directory DIR.\n\ 400*60165Shibler In Unix-syntax, this just removes the final slash.\n\ 401*60165Shibler On VMS, given a VMS-syntax directory name such as \"[X.Y]\",\n\ 402*60165Shibler returns a file name such as \"[X]Y.DIR.1\".") 403*60165Shibler (directory) 404*60165Shibler Lisp_Object directory; 405*60165Shibler { 406*60165Shibler char *buf; 407*60165Shibler 408*60165Shibler CHECK_STRING (directory, 0); 409*60165Shibler 410*60165Shibler if (NULL (directory)) 411*60165Shibler return Qnil; 412*60165Shibler #ifdef VMS 413*60165Shibler /* 20 extra chars is insufficient for VMS, since we might perform a 414*60165Shibler logical name translation. an equivalence string can be up to 255 415*60165Shibler chars long, so grab that much extra space... - sss */ 416*60165Shibler buf = (char *) alloca (XSTRING (directory)->size + 20 + 255); 417*60165Shibler #else 418*60165Shibler buf = (char *) alloca (XSTRING (directory)->size + 20); 419*60165Shibler #endif 420*60165Shibler directory_file_name (XSTRING (directory)->data, buf); 421*60165Shibler return build_string (buf); 422*60165Shibler } 423*60165Shibler 424*60165Shibler DEFUN ("make-temp-name", Fmake_temp_name, Smake_temp_name, 1, 1, 0, 425*60165Shibler "Generate temporary name (string) starting with PREFIX (a string).") 426*60165Shibler (prefix) 427*60165Shibler Lisp_Object prefix; 428*60165Shibler { 429*60165Shibler Lisp_Object val; 430*60165Shibler val = concat2 (prefix, build_string ("XXXXXX")); 431*60165Shibler mktemp (XSTRING (val)->data); 432*60165Shibler return val; 433*60165Shibler } 434*60165Shibler 435*60165Shibler DEFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0, 436*60165Shibler "Convert FILENAME to absolute, and canonicalize it.\n\ 437*60165Shibler Second arg DEFAULT is directory to start with if FILENAME is relative\n\ 438*60165Shibler (does not start with slash); if DEFAULT is nil or missing,\n\ 439*60165Shibler the current buffer's value of default-directory is used.\n\ 440*60165Shibler Filenames containing . or .. as components are simplified;\n\ 441*60165Shibler initial ~ is expanded. See also the function substitute-in-file-name.") 442*60165Shibler (name, defalt) 443*60165Shibler Lisp_Object name, defalt; 444*60165Shibler { 445*60165Shibler unsigned char *nm; 446*60165Shibler 447*60165Shibler register unsigned char *newdir, *p, *o; 448*60165Shibler int tlen; 449*60165Shibler unsigned char *target; 450*60165Shibler struct passwd *pw; 451*60165Shibler int lose; 452*60165Shibler #ifdef VMS 453*60165Shibler unsigned char * colon = 0; 454*60165Shibler unsigned char * close = 0; 455*60165Shibler unsigned char * slash = 0; 456*60165Shibler unsigned char * brack = 0; 457*60165Shibler int lbrack = 0, rbrack = 0; 458*60165Shibler int dots = 0; 459*60165Shibler #endif /* VMS */ 460*60165Shibler 461*60165Shibler CHECK_STRING (name, 0); 462*60165Shibler 463*60165Shibler #ifdef VMS 464*60165Shibler /* Filenames on VMS are always upper case. */ 465*60165Shibler name = Fupcase (name); 466*60165Shibler #endif 467*60165Shibler 468*60165Shibler nm = XSTRING (name)->data; 469*60165Shibler 470*60165Shibler /* If nm is absolute, flush ...// and detect /./ and /../. 471*60165Shibler If no /./ or /../ we can return right away. */ 472*60165Shibler if ( 473*60165Shibler nm[0] == '/' 474*60165Shibler #ifdef VMS 475*60165Shibler || index (nm, ':') 476*60165Shibler #endif /* VMS */ 477*60165Shibler ) 478*60165Shibler { 479*60165Shibler p = nm; 480*60165Shibler lose = 0; 481*60165Shibler while (*p) 482*60165Shibler { 483*60165Shibler if (p[0] == '/' && p[1] == '/' 484*60165Shibler #ifdef APOLLO 485*60165Shibler /* // at start of filename is meaningful on Apollo system */ 486*60165Shibler && nm != p 487*60165Shibler #endif /* APOLLO */ 488*60165Shibler ) 489*60165Shibler nm = p + 1; 490*60165Shibler if (p[0] == '/' && p[1] == '~') 491*60165Shibler nm = p + 1, lose = 1; 492*60165Shibler if (p[0] == '/' && p[1] == '.' 493*60165Shibler && (p[2] == '/' || p[2] == 0 494*60165Shibler || (p[2] == '.' && (p[3] == '/' || p[3] == 0)))) 495*60165Shibler lose = 1; 496*60165Shibler #ifdef VMS 497*60165Shibler if (p[0] == '\\') 498*60165Shibler lose = 1; 499*60165Shibler if (p[0] == '/') { 500*60165Shibler /* if dev:[dir]/, move nm to / */ 501*60165Shibler if (!slash && p > nm && (brack || colon)) { 502*60165Shibler nm = (brack ? brack + 1 : colon + 1); 503*60165Shibler lbrack = rbrack = 0; 504*60165Shibler brack = 0; 505*60165Shibler colon = 0; 506*60165Shibler } 507*60165Shibler slash = p; 508*60165Shibler } 509*60165Shibler if (p[0] == '-') 510*60165Shibler #ifndef VMS4_4 511*60165Shibler /* VMS pre V4.4,convert '-'s in filenames. */ 512*60165Shibler if (lbrack == rbrack) 513*60165Shibler { 514*60165Shibler if (dots < 2) /* this is to allow negative version numbers */ 515*60165Shibler p[0] = '_'; 516*60165Shibler } 517*60165Shibler else 518*60165Shibler #endif /* VMS4_4 */ 519*60165Shibler if (lbrack > rbrack && 520*60165Shibler ((p[-1] == '.' || p[-1] == '[' || p[-1] == '<') && 521*60165Shibler (p[1] == '.' || p[1] == ']' || p[1] == '>'))) 522*60165Shibler lose = 1; 523*60165Shibler #ifndef VMS4_4 524*60165Shibler else 525*60165Shibler p[0] = '_'; 526*60165Shibler #endif /* VMS4_4 */ 527*60165Shibler /* count open brackets, reset close bracket pointer */ 528*60165Shibler if (p[0] == '[' || p[0] == '<') 529*60165Shibler lbrack++, brack = 0; 530*60165Shibler /* count close brackets, set close bracket pointer */ 531*60165Shibler if (p[0] == ']' || p[0] == '>') 532*60165Shibler rbrack++, brack = p; 533*60165Shibler /* detect ][ or >< */ 534*60165Shibler if ((p[0] == ']' || p[0] == '>') && (p[1] == '[' || p[1] == '<')) 535*60165Shibler lose = 1; 536*60165Shibler if ((p[0] == ':' || p[0] == ']' || p[0] == '>') && p[1] == '~') 537*60165Shibler nm = p + 1, lose = 1; 538*60165Shibler if (p[0] == ':' && (colon || slash)) 539*60165Shibler /* if dev1:[dir]dev2:, move nm to dev2: */ 540*60165Shibler if (brack) 541*60165Shibler { 542*60165Shibler nm = brack + 1; 543*60165Shibler brack = 0; 544*60165Shibler } 545*60165Shibler /* if /pathname/dev:, move nm to dev: */ 546*60165Shibler else if (slash) 547*60165Shibler nm = slash + 1; 548*60165Shibler /* if node::dev:, move colon following dev */ 549*60165Shibler else if (colon && colon[-1] == ':') 550*60165Shibler colon = p; 551*60165Shibler /* if dev1:dev2:, move nm to dev2: */ 552*60165Shibler else if (colon && colon[-1] != ':') 553*60165Shibler { 554*60165Shibler nm = colon + 1; 555*60165Shibler colon = 0; 556*60165Shibler } 557*60165Shibler if (p[0] == ':' && !colon) 558*60165Shibler { 559*60165Shibler if (p[1] == ':') 560*60165Shibler p++; 561*60165Shibler colon = p; 562*60165Shibler } 563*60165Shibler if (lbrack == rbrack) 564*60165Shibler if (p[0] == ';') 565*60165Shibler dots = 2; 566*60165Shibler else if (p[0] == '.') 567*60165Shibler dots++; 568*60165Shibler #endif /* VMS */ 569*60165Shibler p++; 570*60165Shibler } 571*60165Shibler if (!lose) 572*60165Shibler { 573*60165Shibler #ifdef VMS 574*60165Shibler if (index (nm, '/')) 575*60165Shibler return build_string (sys_translate_unix (nm)); 576*60165Shibler #endif /* VMS */ 577*60165Shibler if (nm == XSTRING (name)->data) 578*60165Shibler return name; 579*60165Shibler return build_string (nm); 580*60165Shibler } 581*60165Shibler } 582*60165Shibler 583*60165Shibler /* Now determine directory to start with and put it in NEWDIR. */ 584*60165Shibler 585*60165Shibler newdir = 0; 586*60165Shibler 587*60165Shibler if (nm[0] == '~') 588*60165Shibler { 589*60165Shibler if (nm[1] == '/' 590*60165Shibler #ifdef VMS 591*60165Shibler || nm[1] == ':' 592*60165Shibler #endif /* VMS */ 593*60165Shibler || nm[1] == 0) 594*60165Shibler { 595*60165Shibler /* Handle ~ on its own. */ 596*60165Shibler newdir = (unsigned char *) egetenv ("HOME"); 597*60165Shibler } 598*60165Shibler else 599*60165Shibler { 600*60165Shibler /* Handle ~ followed by user name. */ 601*60165Shibler unsigned char *user = nm + 1; 602*60165Shibler /* Find end of name. */ 603*60165Shibler unsigned char *ptr = (unsigned char *) index (user, '/'); 604*60165Shibler int len = ptr ? ptr - user : strlen (user); 605*60165Shibler #ifdef VMS 606*60165Shibler unsigned char *ptr1 = index (user, ':'); 607*60165Shibler if (ptr1 != 0 && ptr1 - user < len) 608*60165Shibler len = ptr1 - user; 609*60165Shibler #endif /* VMS */ 610*60165Shibler /* Copy the user name into temp storage. */ 611*60165Shibler o = (unsigned char *) alloca (len + 1); 612*60165Shibler bcopy ((char *) user, o, len); 613*60165Shibler o[len] = 0; 614*60165Shibler 615*60165Shibler /* Look up the user name. */ 616*60165Shibler pw = (struct passwd *) getpwnam (o); 617*60165Shibler if (!pw) 618*60165Shibler error ("User \"%s\" is not known", o); 619*60165Shibler newdir = (unsigned char *) pw->pw_dir; 620*60165Shibler 621*60165Shibler /* Discard the user name from NM. */ 622*60165Shibler nm += len; 623*60165Shibler } 624*60165Shibler 625*60165Shibler /* Discard the ~ from NM. */ 626*60165Shibler nm++; 627*60165Shibler #ifdef VMS 628*60165Shibler if (*nm != 0) 629*60165Shibler nm++; /* Don't leave the slash in nm. */ 630*60165Shibler #endif /* VMS */ 631*60165Shibler 632*60165Shibler if (newdir == 0) 633*60165Shibler newdir = (unsigned char *) ""; 634*60165Shibler } 635*60165Shibler 636*60165Shibler if (nm[0] != '/' 637*60165Shibler #ifdef VMS 638*60165Shibler && !index (nm, ':') 639*60165Shibler #endif /* not VMS */ 640*60165Shibler && !newdir) 641*60165Shibler { 642*60165Shibler if (NULL (defalt)) 643*60165Shibler defalt = current_buffer->directory; 644*60165Shibler CHECK_STRING (defalt, 1); 645*60165Shibler newdir = XSTRING (defalt)->data; 646*60165Shibler } 647*60165Shibler 648*60165Shibler /* Now concatenate the directory and name to new space in the stack frame */ 649*60165Shibler 650*60165Shibler tlen = (newdir ? strlen (newdir) + 1 : 0) + strlen (nm) + 1; 651*60165Shibler target = (unsigned char *) alloca (tlen); 652*60165Shibler *target = 0; 653*60165Shibler 654*60165Shibler if (newdir) 655*60165Shibler { 656*60165Shibler #ifndef VMS 657*60165Shibler if (nm[0] == 0 || nm[0] == '/') 658*60165Shibler strcpy (target, newdir); 659*60165Shibler else 660*60165Shibler #endif 661*60165Shibler file_name_as_directory (target, newdir); 662*60165Shibler } 663*60165Shibler 664*60165Shibler strcat (target, nm); 665*60165Shibler #ifdef VMS 666*60165Shibler if (index (target, '/')) 667*60165Shibler strcpy (target, sys_translate_unix (target)); 668*60165Shibler #endif /* VMS */ 669*60165Shibler 670*60165Shibler /* Now canonicalize by removing /. and /foo/.. if they appear */ 671*60165Shibler 672*60165Shibler p = target; 673*60165Shibler o = target; 674*60165Shibler 675*60165Shibler while (*p) 676*60165Shibler { 677*60165Shibler #ifdef VMS 678*60165Shibler if (*p != ']' && *p != '>' && *p != '-') 679*60165Shibler { 680*60165Shibler if (*p == '\\') 681*60165Shibler p++; 682*60165Shibler *o++ = *p++; 683*60165Shibler } 684*60165Shibler else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2) 685*60165Shibler /* brackets are offset from each other by 2 */ 686*60165Shibler { 687*60165Shibler p += 2; 688*60165Shibler if (*p != '.' && *p != '-' && o[-1] != '.') 689*60165Shibler /* convert [foo][bar] to [bar] */ 690*60165Shibler while (o[-1] != '[' && o[-1] != '<') 691*60165Shibler o--; 692*60165Shibler else if (*p == '-' && *o != '.') 693*60165Shibler *--p = '.'; 694*60165Shibler } 695*60165Shibler else if (p[0] == '-' && o[-1] == '.' && 696*60165Shibler (p[1] == '.' || p[1] == ']' || p[1] == '>')) 697*60165Shibler /* flush .foo.- ; leave - if stopped by '[' or '<' */ 698*60165Shibler { 699*60165Shibler do 700*60165Shibler o--; 701*60165Shibler while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<'); 702*60165Shibler if (p[1] == '.') /* foo.-.bar ==> bar*/ 703*60165Shibler p += 2; 704*60165Shibler else if (o[-1] == '.') /* '.foo.-]' ==> ']' */ 705*60165Shibler p++, o--; 706*60165Shibler /* else [foo.-] ==> [-] */ 707*60165Shibler } 708*60165Shibler else 709*60165Shibler { 710*60165Shibler #ifndef VMS4_4 711*60165Shibler if (*p == '-' && 712*60165Shibler o[-1] != '[' && o[-1] != '<' && o[-1] != '.' && 713*60165Shibler p[1] != ']' && p[1] != '>' && p[1] != '.') 714*60165Shibler *p = '_'; 715*60165Shibler #endif /* VMS4_4 */ 716*60165Shibler *o++ = *p++; 717*60165Shibler } 718*60165Shibler #else /* not VMS */ 719*60165Shibler if (*p != '/') 720*60165Shibler { 721*60165Shibler *o++ = *p++; 722*60165Shibler } 723*60165Shibler else if (!strncmp (p, "//", 2) 724*60165Shibler #ifdef APOLLO 725*60165Shibler /* // at start of filename is meaningful in Apollo system */ 726*60165Shibler && o != target 727*60165Shibler #endif /* APOLLO */ 728*60165Shibler ) 729*60165Shibler { 730*60165Shibler o = target; 731*60165Shibler p++; 732*60165Shibler } 733*60165Shibler else if (p[0] == '/' && p[1] == '.' && 734*60165Shibler (p[2] == '/' || p[2] == 0)) 735*60165Shibler p += 2; 736*60165Shibler else if (!strncmp (p, "/..", 3) 737*60165Shibler /* `/../' is the "superroot" on certain file systems. */ 738*60165Shibler && o != target 739*60165Shibler && (p[3] == '/' || p[3] == 0)) 740*60165Shibler { 741*60165Shibler while (o != target && *--o != '/') 742*60165Shibler ; 743*60165Shibler #ifdef APOLLO 744*60165Shibler if (o == target + 1 && o[-1] == '/' && o[0] == '/') 745*60165Shibler ++o; 746*60165Shibler else 747*60165Shibler #endif APOLLO 748*60165Shibler if (o == target && *o == '/') 749*60165Shibler ++o; 750*60165Shibler p += 3; 751*60165Shibler } 752*60165Shibler else 753*60165Shibler { 754*60165Shibler *o++ = *p++; 755*60165Shibler } 756*60165Shibler #endif /* not VMS */ 757*60165Shibler } 758*60165Shibler 759*60165Shibler return make_string (target, o - target); 760*60165Shibler } 761*60165Shibler 762*60165Shibler DEFUN ("substitute-in-file-name", Fsubstitute_in_file_name, 763*60165Shibler Ssubstitute_in_file_name, 1, 1, 0, 764*60165Shibler "Substitute environment variables referred to in STRING.\n\ 765*60165Shibler A $ begins a request to substitute; the env variable name is the alphanumeric\n\ 766*60165Shibler characters and underscores after the $, or is surrounded by braces.\n\ 767*60165Shibler If a ~ appears following a /, everything through that / is discarded.\n\ 768*60165Shibler On VMS, $ substitution is not done; this function does little and only\n\ 769*60165Shibler duplicates what expand-file-name does.") 770*60165Shibler (string) 771*60165Shibler Lisp_Object string; 772*60165Shibler { 773*60165Shibler unsigned char *nm; 774*60165Shibler 775*60165Shibler register unsigned char *s, *p, *o, *x, *endp; 776*60165Shibler unsigned char *target; 777*60165Shibler int total = 0; 778*60165Shibler int substituted = 0; 779*60165Shibler unsigned char *xnm; 780*60165Shibler 781*60165Shibler CHECK_STRING (string, 0); 782*60165Shibler 783*60165Shibler nm = XSTRING (string)->data; 784*60165Shibler endp = nm + XSTRING (string)->size; 785*60165Shibler 786*60165Shibler /* If /~ or // appears, discard everything through first slash. */ 787*60165Shibler 788*60165Shibler for (p = nm; p != endp; p++) 789*60165Shibler { 790*60165Shibler if ((p[0] == '~' || 791*60165Shibler #ifdef APOLLO 792*60165Shibler /* // at start of file name is meaningful in Apollo system */ 793*60165Shibler (p[0] == '/' && p - 1 != nm) 794*60165Shibler #else /* not APOLLO */ 795*60165Shibler p[0] == '/' 796*60165Shibler #endif /* not APOLLO */ 797*60165Shibler ) 798*60165Shibler && p != nm && 799*60165Shibler #ifdef VMS 800*60165Shibler (p[-1] == ':' || p[-1] == ']' || p[-1] == '>' || 801*60165Shibler #endif /* VMS */ 802*60165Shibler p[-1] == '/') 803*60165Shibler #ifdef VMS 804*60165Shibler ) 805*60165Shibler #endif /* VMS */ 806*60165Shibler { 807*60165Shibler nm = p; 808*60165Shibler substituted = 1; 809*60165Shibler } 810*60165Shibler } 811*60165Shibler 812*60165Shibler #ifdef VMS 813*60165Shibler return build_string (nm); 814*60165Shibler #else 815*60165Shibler 816*60165Shibler /* See if any variables are substituted into the string 817*60165Shibler and find the total length of their values in `total' */ 818*60165Shibler 819*60165Shibler for (p = nm; p != endp;) 820*60165Shibler if (*p != '$') 821*60165Shibler p++; 822*60165Shibler else 823*60165Shibler { 824*60165Shibler p++; 825*60165Shibler if (p == endp) 826*60165Shibler goto badsubst; 827*60165Shibler else if (*p == '$') 828*60165Shibler { 829*60165Shibler /* "$$" means a single "$" */ 830*60165Shibler p++; 831*60165Shibler total -= 1; 832*60165Shibler substituted = 1; 833*60165Shibler continue; 834*60165Shibler } 835*60165Shibler else if (*p == '{') 836*60165Shibler { 837*60165Shibler o = ++p; 838*60165Shibler while (p != endp && *p != '}') p++; 839*60165Shibler if (*p != '}') goto missingclose; 840*60165Shibler s = p; 841*60165Shibler } 842*60165Shibler else 843*60165Shibler { 844*60165Shibler o = p; 845*60165Shibler while (p != endp && (isalnum (*p) || *p == '_')) p++; 846*60165Shibler s = p; 847*60165Shibler } 848*60165Shibler 849*60165Shibler /* Copy out the variable name */ 850*60165Shibler target = (unsigned char *) alloca (s - o + 1); 851*60165Shibler strncpy (target, o, s - o); 852*60165Shibler target[s - o] = 0; 853*60165Shibler 854*60165Shibler /* Get variable value */ 855*60165Shibler o = (unsigned char *) egetenv (target); 856*60165Shibler /* The presence of this code makes vax 5.0 crash, for reasons yet unknown */ 857*60165Shibler #if 0 858*60165Shibler #ifdef USG 859*60165Shibler if (!o && !strcmp (target, "USER")) 860*60165Shibler o = egetenv ("LOGNAME"); 861*60165Shibler #endif /* USG */ 862*60165Shibler #endif /* 0 */ 863*60165Shibler if (!o) goto badvar; 864*60165Shibler total += strlen (o); 865*60165Shibler substituted = 1; 866*60165Shibler } 867*60165Shibler 868*60165Shibler if (!substituted) 869*60165Shibler return string; 870*60165Shibler 871*60165Shibler /* If substitution required, recopy the string and do it */ 872*60165Shibler /* Make space in stack frame for the new copy */ 873*60165Shibler xnm = (unsigned char *) alloca (XSTRING (string)->size + total + 1); 874*60165Shibler x = xnm; 875*60165Shibler 876*60165Shibler /* Copy the rest of the name through, replacing $ constructs with values */ 877*60165Shibler for (p = nm; *p;) 878*60165Shibler if (*p != '$') 879*60165Shibler *x++ = *p++; 880*60165Shibler else 881*60165Shibler { 882*60165Shibler p++; 883*60165Shibler if (p == endp) 884*60165Shibler goto badsubst; 885*60165Shibler else if (*p == '$') 886*60165Shibler { 887*60165Shibler *x++ = *p++; 888*60165Shibler continue; 889*60165Shibler } 890*60165Shibler else if (*p == '{') 891*60165Shibler { 892*60165Shibler o = ++p; 893*60165Shibler while (p != endp && *p != '}') p++; 894*60165Shibler if (*p != '}') goto missingclose; 895*60165Shibler s = p++; 896*60165Shibler } 897*60165Shibler else 898*60165Shibler { 899*60165Shibler o = p; 900*60165Shibler while (p != endp && (isalnum (*p) || *p == '_')) p++; 901*60165Shibler s = p; 902*60165Shibler } 903*60165Shibler 904*60165Shibler /* Copy out the variable name */ 905*60165Shibler target = (unsigned char *) alloca (s - o + 1); 906*60165Shibler strncpy (target, o, s - o); 907*60165Shibler target[s - o] = 0; 908*60165Shibler 909*60165Shibler /* Get variable value */ 910*60165Shibler o = (unsigned char *) egetenv (target); 911*60165Shibler /* The presence of this code makes vax 5.0 crash, for reasons yet unknown */ 912*60165Shibler #if 0 913*60165Shibler #ifdef USG 914*60165Shibler if (!o && !strcmp (target, "USER")) 915*60165Shibler o = egetenv ("LOGNAME"); 916*60165Shibler #endif /* USG */ 917*60165Shibler #endif /* 0 */ 918*60165Shibler if (!o) 919*60165Shibler goto badvar; 920*60165Shibler 921*60165Shibler strcpy (x, o); 922*60165Shibler x += strlen (o); 923*60165Shibler } 924*60165Shibler 925*60165Shibler *x = 0; 926*60165Shibler 927*60165Shibler /* If /~ or // appears, discard everything through first slash. */ 928*60165Shibler 929*60165Shibler for (p = xnm; p != x; p++) 930*60165Shibler if ((p[0] == '~' || 931*60165Shibler #ifdef APOLLO 932*60165Shibler /* // at start of file name is meaningful in Apollo system */ 933*60165Shibler (p[0] == '/' && p - 1 != xnm) 934*60165Shibler #else /* not APOLLO */ 935*60165Shibler p[0] == '/' 936*60165Shibler #endif /* not APOLLO */ 937*60165Shibler ) 938*60165Shibler && p != nm && p[-1] == '/') 939*60165Shibler xnm = p; 940*60165Shibler 941*60165Shibler return make_string (xnm, x - xnm); 942*60165Shibler 943*60165Shibler badsubst: 944*60165Shibler error ("Bad format environment-variable substitution"); 945*60165Shibler missingclose: 946*60165Shibler error ("Missing \"}\" in environment-variable substitution"); 947*60165Shibler badvar: 948*60165Shibler error ("Substituting nonexistent environment variable \"%s\"", target); 949*60165Shibler 950*60165Shibler /* NOTREACHED */ 951*60165Shibler #endif /* not VMS */ 952*60165Shibler } 953*60165Shibler 954*60165Shibler Lisp_Object 955*60165Shibler expand_and_dir_to_file (filename, defdir) 956*60165Shibler Lisp_Object filename, defdir; 957*60165Shibler { 958*60165Shibler register Lisp_Object abspath; 959*60165Shibler 960*60165Shibler abspath = Fexpand_file_name (filename, defdir); 961*60165Shibler #ifdef VMS 962*60165Shibler { 963*60165Shibler register int c = XSTRING (abspath)->data[XSTRING (abspath)->size - 1]; 964*60165Shibler if (c == ':' || c == ']' || c == '>') 965*60165Shibler abspath = Fdirectory_file_name (abspath); 966*60165Shibler } 967*60165Shibler #else 968*60165Shibler /* Remove final slash, if any (unless path is root). 969*60165Shibler stat behaves differently depending! */ 970*60165Shibler if (XSTRING (abspath)->size > 1 971*60165Shibler && XSTRING (abspath)->data[XSTRING (abspath)->size - 1] == '/') 972*60165Shibler { 973*60165Shibler if (EQ (abspath, filename)) 974*60165Shibler abspath = Fcopy_sequence (abspath); 975*60165Shibler XSTRING (abspath)->data[XSTRING (abspath)->size - 1] = 0; 976*60165Shibler } 977*60165Shibler #endif 978*60165Shibler return abspath; 979*60165Shibler } 980*60165Shibler 981*60165Shibler barf_or_query_if_file_exists (absname, querystring, interactive) 982*60165Shibler Lisp_Object absname; 983*60165Shibler unsigned char *querystring; 984*60165Shibler int interactive; 985*60165Shibler { 986*60165Shibler register Lisp_Object tem; 987*60165Shibler struct gcpro gcpro1; 988*60165Shibler 989*60165Shibler if (access (XSTRING (absname)->data, 4) >= 0) 990*60165Shibler { 991*60165Shibler if (! interactive) 992*60165Shibler Fsignal (Qfile_already_exists, 993*60165Shibler Fcons (build_string ("File already exists"), 994*60165Shibler Fcons (absname, Qnil))); 995*60165Shibler GCPRO1 (absname); 996*60165Shibler tem = Fyes_or_no_p (format1 ("File %s already exists; %s anyway? ", 997*60165Shibler XSTRING (absname)->data, querystring)); 998*60165Shibler UNGCPRO; 999*60165Shibler if (NULL (tem)) 1000*60165Shibler Fsignal (Qfile_already_exists, 1001*60165Shibler Fcons (build_string ("File already exists"), 1002*60165Shibler Fcons (absname, Qnil))); 1003*60165Shibler } 1004*60165Shibler return; 1005*60165Shibler } 1006*60165Shibler 1007*60165Shibler DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 4, 1008*60165Shibler "fCopy file: \nFCopy %s to file: \np", 1009*60165Shibler "Copy FILE to NEWNAME. Both args strings.\n\ 1010*60165Shibler Signals a file-already-exists error if NEWNAME already exists,\n\ 1011*60165Shibler unless a third argument OK-IF-ALREADY-EXISTS is supplied and non-nil.\n\ 1012*60165Shibler A number as third arg means request confirmation if NEWNAME already exists.\n\ 1013*60165Shibler This is what happens in interactive use with M-x.\n\ 1014*60165Shibler Fourth arg non-nil means give the new file the same last-modified time\n\ 1015*60165Shibler that the old one has. (This works on only some systems.)") 1016*60165Shibler (filename, newname, ok_if_already_exists, keep_date) 1017*60165Shibler Lisp_Object filename, newname, ok_if_already_exists, keep_date; 1018*60165Shibler { 1019*60165Shibler int ifd, ofd, n; 1020*60165Shibler char buf[16 * 1024]; 1021*60165Shibler struct stat st; 1022*60165Shibler struct gcpro gcpro1, gcpro2; 1023*60165Shibler 1024*60165Shibler GCPRO2 (filename, newname); 1025*60165Shibler CHECK_STRING (filename, 0); 1026*60165Shibler CHECK_STRING (newname, 1); 1027*60165Shibler filename = Fexpand_file_name (filename, Qnil); 1028*60165Shibler newname = Fexpand_file_name (newname, Qnil); 1029*60165Shibler if (NULL (ok_if_already_exists) 1030*60165Shibler || XTYPE (ok_if_already_exists) == Lisp_Int) 1031*60165Shibler barf_or_query_if_file_exists (newname, "copy to it", 1032*60165Shibler XTYPE (ok_if_already_exists) == Lisp_Int); 1033*60165Shibler 1034*60165Shibler ifd = open (XSTRING (filename)->data, 0); 1035*60165Shibler if (ifd < 0) 1036*60165Shibler report_file_error ("Opening input file", Fcons (filename, Qnil)); 1037*60165Shibler 1038*60165Shibler #ifdef VMS 1039*60165Shibler /* Create the copy file with the same record format as the input file */ 1040*60165Shibler ofd = sys_creat (XSTRING (newname)->data, 0666, ifd); 1041*60165Shibler #else 1042*60165Shibler ofd = creat (XSTRING (newname)->data, 0666); 1043*60165Shibler #endif /* VMS */ 1044*60165Shibler if (ofd < 0) 1045*60165Shibler { 1046*60165Shibler close (ifd); 1047*60165Shibler report_file_error ("Opening output file", Fcons (newname, Qnil)); 1048*60165Shibler } 1049*60165Shibler 1050*60165Shibler while ((n = read (ifd, buf, sizeof buf)) > 0) 1051*60165Shibler if (write (ofd, buf, n) != n) 1052*60165Shibler { 1053*60165Shibler close (ifd); 1054*60165Shibler close (ofd); 1055*60165Shibler report_file_error ("I/O error", Fcons (newname, Qnil)); 1056*60165Shibler } 1057*60165Shibler 1058*60165Shibler if (fstat (ifd, &st) >= 0) 1059*60165Shibler { 1060*60165Shibler #ifdef HAVE_TIMEVAL 1061*60165Shibler if (!NULL (keep_date)) 1062*60165Shibler { 1063*60165Shibler #ifdef USE_UTIME 1064*60165Shibler /* AIX has utimes() in compatibility package, but it dies. So use good old 1065*60165Shibler utime interface instead. */ 1066*60165Shibler struct { 1067*60165Shibler time_t atime; 1068*60165Shibler time_t mtime; 1069*60165Shibler } tv; 1070*60165Shibler tv.atime = st.st_atime; 1071*60165Shibler tv.mtime = st.st_mtime; 1072*60165Shibler utime (XSTRING (newname)->data, &tv); 1073*60165Shibler #else /* not USE_UTIME */ 1074*60165Shibler struct timeval timevals[2]; 1075*60165Shibler timevals[0].tv_sec = st.st_atime; 1076*60165Shibler timevals[1].tv_sec = st.st_mtime; 1077*60165Shibler timevals[0].tv_usec = timevals[1].tv_usec = 0; 1078*60165Shibler utimes (XSTRING (newname)->data, timevals); 1079*60165Shibler #endif /* not USE_UTIME */ 1080*60165Shibler } 1081*60165Shibler #endif /* HAVE_TIMEVALS */ 1082*60165Shibler 1083*60165Shibler #ifdef APOLLO 1084*60165Shibler if (!egetenv ("USE_DOMAIN_ACLS")) 1085*60165Shibler #endif 1086*60165Shibler chmod (XSTRING (newname)->data, st.st_mode & 07777); 1087*60165Shibler } 1088*60165Shibler 1089*60165Shibler close (ifd); 1090*60165Shibler if (close (ofd) < 0) 1091*60165Shibler report_file_error ("I/O error", Fcons (newname, Qnil)); 1092*60165Shibler 1093*60165Shibler UNGCPRO; 1094*60165Shibler return Qnil; 1095*60165Shibler } 1096*60165Shibler 1097*60165Shibler DEFUN ("delete-file", Fdelete_file, Sdelete_file, 1, 1, "fDelete file: ", 1098*60165Shibler "Delete specified file. One argument, a file name string.\n\ 1099*60165Shibler If file has multiple names, it continues to exist with the other names.") 1100*60165Shibler (filename) 1101*60165Shibler Lisp_Object filename; 1102*60165Shibler { 1103*60165Shibler CHECK_STRING (filename, 0); 1104*60165Shibler filename = Fexpand_file_name (filename, Qnil); 1105*60165Shibler if (0 > unlink (XSTRING (filename)->data)) 1106*60165Shibler report_file_error ("Removing old name", Flist (1, &filename)); 1107*60165Shibler return Qnil; 1108*60165Shibler } 1109*60165Shibler 1110*60165Shibler DEFUN ("rename-file", Frename_file, Srename_file, 2, 3, 1111*60165Shibler "fRename file: \nFRename %s to file: \np", 1112*60165Shibler "Rename FILE as NEWNAME. Both args strings.\n\ 1113*60165Shibler If file has names other than FILE, it continues to have those names.\n\ 1114*60165Shibler Signals a file-already-exists error if NEWNAME already exists\n\ 1115*60165Shibler unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\ 1116*60165Shibler A number as third arg means request confirmation if NEWNAME already exists.\n\ 1117*60165Shibler This is what happens in interactive use with M-x.") 1118*60165Shibler (filename, newname, ok_if_already_exists) 1119*60165Shibler Lisp_Object filename, newname, ok_if_already_exists; 1120*60165Shibler { 1121*60165Shibler #ifdef NO_ARG_ARRAY 1122*60165Shibler Lisp_Object args[2]; 1123*60165Shibler #endif 1124*60165Shibler struct gcpro gcpro1, gcpro2; 1125*60165Shibler 1126*60165Shibler GCPRO2 (filename, newname); 1127*60165Shibler CHECK_STRING (filename, 0); 1128*60165Shibler CHECK_STRING (newname, 1); 1129*60165Shibler filename = Fexpand_file_name (filename, Qnil); 1130*60165Shibler newname = Fexpand_file_name (newname, Qnil); 1131*60165Shibler if (NULL (ok_if_already_exists) 1132*60165Shibler || XTYPE (ok_if_already_exists) == Lisp_Int) 1133*60165Shibler barf_or_query_if_file_exists (newname, "rename to it", 1134*60165Shibler XTYPE (ok_if_already_exists) == Lisp_Int); 1135*60165Shibler #ifndef BSD4_1 1136*60165Shibler if (0 > rename (XSTRING (filename)->data, XSTRING (newname)->data)) 1137*60165Shibler #else 1138*60165Shibler if (0 > link (XSTRING (filename)->data, XSTRING (newname)->data) 1139*60165Shibler || 0 > unlink (XSTRING (filename)->data)) 1140*60165Shibler #endif 1141*60165Shibler { 1142*60165Shibler if (errno == EXDEV) 1143*60165Shibler { 1144*60165Shibler Fcopy_file (filename, newname, ok_if_already_exists, Qt); 1145*60165Shibler Fdelete_file (filename); 1146*60165Shibler } 1147*60165Shibler else 1148*60165Shibler #ifdef NO_ARG_ARRAY 1149*60165Shibler { 1150*60165Shibler args[0] = filename; 1151*60165Shibler args[1] = newname; 1152*60165Shibler report_file_error ("Renaming", Flist (2, args)); 1153*60165Shibler } 1154*60165Shibler #else 1155*60165Shibler report_file_error ("Renaming", Flist (2, &filename)); 1156*60165Shibler #endif 1157*60165Shibler } 1158*60165Shibler UNGCPRO; 1159*60165Shibler return Qnil; 1160*60165Shibler } 1161*60165Shibler 1162*60165Shibler DEFUN ("add-name-to-file", Fadd_name_to_file, Sadd_name_to_file, 2, 3, 1163*60165Shibler "fAdd name to file: \nFName to add to %s: \np", 1164*60165Shibler "Give FILE additional name NEWNAME. Both args strings.\n\ 1165*60165Shibler Signals a file-already-exists error if NEWNAME already exists\n\ 1166*60165Shibler unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\ 1167*60165Shibler A number as third arg means request confirmation if NEWNAME already exists.\n\ 1168*60165Shibler This is what happens in interactive use with M-x.") 1169*60165Shibler (filename, newname, ok_if_already_exists) 1170*60165Shibler Lisp_Object filename, newname, ok_if_already_exists; 1171*60165Shibler { 1172*60165Shibler #ifdef NO_ARG_ARRAY 1173*60165Shibler Lisp_Object args[2]; 1174*60165Shibler #endif 1175*60165Shibler struct gcpro gcpro1, gcpro2; 1176*60165Shibler 1177*60165Shibler GCPRO2 (filename, newname); 1178*60165Shibler CHECK_STRING (filename, 0); 1179*60165Shibler CHECK_STRING (newname, 1); 1180*60165Shibler filename = Fexpand_file_name (filename, Qnil); 1181*60165Shibler newname = Fexpand_file_name (newname, Qnil); 1182*60165Shibler if (NULL (ok_if_already_exists) 1183*60165Shibler || XTYPE (ok_if_already_exists) == Lisp_Int) 1184*60165Shibler barf_or_query_if_file_exists (newname, "make it a new name", 1185*60165Shibler XTYPE (ok_if_already_exists) == Lisp_Int); 1186*60165Shibler unlink (XSTRING (newname)->data); 1187*60165Shibler if (0 > link (XSTRING (filename)->data, XSTRING (newname)->data)) 1188*60165Shibler { 1189*60165Shibler #ifdef NO_ARG_ARRAY 1190*60165Shibler args[0] = filename; 1191*60165Shibler args[1] = newname; 1192*60165Shibler report_file_error ("Adding new name", Flist (2, args)); 1193*60165Shibler #else 1194*60165Shibler report_file_error ("Adding new name", Flist (2, &filename)); 1195*60165Shibler #endif 1196*60165Shibler } 1197*60165Shibler 1198*60165Shibler UNGCPRO; 1199*60165Shibler return Qnil; 1200*60165Shibler } 1201*60165Shibler 1202*60165Shibler #ifdef S_IFLNK 1203*60165Shibler DEFUN ("make-symbolic-link", Fmake_symbolic_link, Smake_symbolic_link, 2, 3, 1204*60165Shibler "FMake symbolic link to file: \nFMake symbolic link to file %s: \np", 1205*60165Shibler "Make a symbolic link to FILENAME, named LINKNAME. Both args strings.\n\ 1206*60165Shibler Signals a file-already-exists error if NEWNAME already exists\n\ 1207*60165Shibler unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\ 1208*60165Shibler A number as third arg means request confirmation if NEWNAME already exists.\n\ 1209*60165Shibler This happens for interactive use with M-x.") 1210*60165Shibler (filename, newname, ok_if_already_exists) 1211*60165Shibler Lisp_Object filename, newname, ok_if_already_exists; 1212*60165Shibler { 1213*60165Shibler #ifdef NO_ARG_ARRAY 1214*60165Shibler Lisp_Object args[2]; 1215*60165Shibler #endif 1216*60165Shibler struct gcpro gcpro1, gcpro2; 1217*60165Shibler 1218*60165Shibler GCPRO2 (filename, newname); 1219*60165Shibler CHECK_STRING (filename, 0); 1220*60165Shibler CHECK_STRING (newname, 1); 1221*60165Shibler filename = Fexpand_file_name (filename, Qnil); 1222*60165Shibler newname = Fexpand_file_name (newname, Qnil); 1223*60165Shibler if (NULL (ok_if_already_exists) 1224*60165Shibler || XTYPE (ok_if_already_exists) == Lisp_Int) 1225*60165Shibler barf_or_query_if_file_exists (newname, "make it a link", 1226*60165Shibler XTYPE (ok_if_already_exists) == Lisp_Int); 1227*60165Shibler if (0 > symlink (XSTRING (filename)->data, XSTRING (newname)->data)) 1228*60165Shibler { 1229*60165Shibler #ifdef NO_ARG_ARRAY 1230*60165Shibler args[0] = filename; 1231*60165Shibler args[1] = newname; 1232*60165Shibler report_file_error ("Making symbolic link", Flist (2, args)); 1233*60165Shibler #else 1234*60165Shibler report_file_error ("Making symbolic link", Flist (2, &filename)); 1235*60165Shibler #endif 1236*60165Shibler } 1237*60165Shibler UNGCPRO; 1238*60165Shibler return Qnil; 1239*60165Shibler } 1240*60165Shibler #endif /* S_IFLNK */ 1241*60165Shibler 1242*60165Shibler #ifdef VMS 1243*60165Shibler 1244*60165Shibler DEFUN ("define-logical-name", Fdefine_logical_name, Sdefine_logical_name, 1245*60165Shibler 2, 2, 1246*60165Shibler "sDefine logical name: \nsDefine logical name %s as: ", 1247*60165Shibler "Define the job-wide logical name NAME to have the value STRING.\n\ 1248*60165Shibler If STRING is nil or a null string, the logical name NAME is deleted.") 1249*60165Shibler (varname, string) 1250*60165Shibler Lisp_Object varname; 1251*60165Shibler Lisp_Object string; 1252*60165Shibler { 1253*60165Shibler CHECK_STRING (varname, 0); 1254*60165Shibler if (NULL (string)) 1255*60165Shibler delete_logical_name (XSTRING (varname)->data); 1256*60165Shibler else 1257*60165Shibler { 1258*60165Shibler CHECK_STRING (string, 1); 1259*60165Shibler 1260*60165Shibler if (XSTRING (string)->size == 0) 1261*60165Shibler delete_logical_name (XSTRING (varname)->data); 1262*60165Shibler else 1263*60165Shibler define_logical_name (XSTRING (varname)->data, XSTRING (string)->data); 1264*60165Shibler } 1265*60165Shibler 1266*60165Shibler return string; 1267*60165Shibler } 1268*60165Shibler #endif /* VMS */ 1269*60165Shibler 1270*60165Shibler #ifdef HPUX_NET 1271*60165Shibler 1272*60165Shibler DEFUN ("sysnetunam", Fsysnetunam, Ssysnetunam, 2, 2, 0, 1273*60165Shibler "Open a network connection to PATH using LOGIN as the login string.") 1274*60165Shibler (path, login) 1275*60165Shibler Lisp_Object path, login; 1276*60165Shibler { 1277*60165Shibler int netresult; 1278*60165Shibler 1279*60165Shibler CHECK_STRING (path, 0); 1280*60165Shibler CHECK_STRING (login, 0); 1281*60165Shibler 1282*60165Shibler netresult = netunam (XSTRING (path)->data, XSTRING (login)->data); 1283*60165Shibler 1284*60165Shibler if (netresult == -1) 1285*60165Shibler return Qnil; 1286*60165Shibler else 1287*60165Shibler return Qt; 1288*60165Shibler } 1289*60165Shibler #endif /* HPUX_NET */ 1290*60165Shibler 1291*60165Shibler DEFUN ("file-name-absolute-p", Ffile_name_absolute_p, Sfile_name_absolute_p, 1292*60165Shibler 1, 1, 0, 1293*60165Shibler "Return t if file FILENAME specifies an absolute path name.") 1294*60165Shibler (filename) 1295*60165Shibler Lisp_Object filename; 1296*60165Shibler { 1297*60165Shibler unsigned char *ptr; 1298*60165Shibler 1299*60165Shibler CHECK_STRING (filename, 0); 1300*60165Shibler ptr = XSTRING (filename)->data; 1301*60165Shibler if (*ptr == '/' || *ptr == '~' 1302*60165Shibler #ifdef VMS 1303*60165Shibler /* ??? This criterion is probably wrong for '<'. */ 1304*60165Shibler || index (ptr, ':') || index (ptr, '<') 1305*60165Shibler || (*ptr == '[' && (ptr[1] != '-' || (ptr[2] != '.' && ptr[2] != ']')) 1306*60165Shibler && ptr[1] != '.') 1307*60165Shibler #endif /* VMS */ 1308*60165Shibler ) 1309*60165Shibler return Qt; 1310*60165Shibler else 1311*60165Shibler return Qnil; 1312*60165Shibler } 1313*60165Shibler 1314*60165Shibler DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0, 1315*60165Shibler "Return t if file FILENAME exists. (This does not mean you can read it.)\n\ 1316*60165Shibler See also file-readable-p and file-attributes.") 1317*60165Shibler (filename) 1318*60165Shibler Lisp_Object filename; 1319*60165Shibler { 1320*60165Shibler Lisp_Object abspath; 1321*60165Shibler 1322*60165Shibler CHECK_STRING (filename, 0); 1323*60165Shibler abspath = Fexpand_file_name (filename, Qnil); 1324*60165Shibler return (access (XSTRING (abspath)->data, 0) >= 0) ? Qt : Qnil; 1325*60165Shibler } 1326*60165Shibler 1327*60165Shibler DEFUN ("file-readable-p", Ffile_readable_p, Sfile_readable_p, 1, 1, 0, 1328*60165Shibler "Return t if file FILENAME exists and you can read it.\n\ 1329*60165Shibler See also file-exists-p and file-attributes.") 1330*60165Shibler (filename) 1331*60165Shibler Lisp_Object filename; 1332*60165Shibler { 1333*60165Shibler Lisp_Object abspath; 1334*60165Shibler 1335*60165Shibler CHECK_STRING (filename, 0); 1336*60165Shibler abspath = Fexpand_file_name (filename, Qnil); 1337*60165Shibler return (access (XSTRING (abspath)->data, 4) >= 0) ? Qt : Qnil; 1338*60165Shibler } 1339*60165Shibler 1340*60165Shibler DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0, 1341*60165Shibler "If file FILENAME is the name of a symbolic link\n\ 1342*60165Shibler returns the name of the file to which it is linked.\n\ 1343*60165Shibler Otherwise returns NIL.") 1344*60165Shibler (filename) 1345*60165Shibler Lisp_Object filename; 1346*60165Shibler { 1347*60165Shibler #ifdef S_IFLNK 1348*60165Shibler char *buf; 1349*60165Shibler int bufsize; 1350*60165Shibler int valsize; 1351*60165Shibler Lisp_Object val; 1352*60165Shibler 1353*60165Shibler CHECK_STRING (filename, 0); 1354*60165Shibler filename = Fexpand_file_name (filename, Qnil); 1355*60165Shibler 1356*60165Shibler bufsize = 100; 1357*60165Shibler while (1) 1358*60165Shibler { 1359*60165Shibler buf = (char *) xmalloc (bufsize); 1360*60165Shibler bzero (buf, bufsize); 1361*60165Shibler valsize = readlink (XSTRING (filename)->data, buf, bufsize); 1362*60165Shibler if (valsize < bufsize) break; 1363*60165Shibler /* Buffer was not long enough */ 1364*60165Shibler free (buf); 1365*60165Shibler bufsize *= 2; 1366*60165Shibler } 1367*60165Shibler if (valsize == -1) 1368*60165Shibler { 1369*60165Shibler free (buf); 1370*60165Shibler return Qnil; 1371*60165Shibler } 1372*60165Shibler val = make_string (buf, valsize); 1373*60165Shibler free (buf); 1374*60165Shibler return val; 1375*60165Shibler #else /* not S_IFLNK */ 1376*60165Shibler return Qnil; 1377*60165Shibler #endif /* not S_IFLNK */ 1378*60165Shibler } 1379*60165Shibler 1380*60165Shibler /* Having this before file-symlink-p mysteriously caused it to be forgotten 1381*60165Shibler on the RT/PC. */ 1382*60165Shibler DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, 1383*60165Shibler "Return t if file FILENAME can be written or created by you.") 1384*60165Shibler (filename) 1385*60165Shibler Lisp_Object filename; 1386*60165Shibler { 1387*60165Shibler Lisp_Object abspath, dir; 1388*60165Shibler 1389*60165Shibler CHECK_STRING (filename, 0); 1390*60165Shibler abspath = Fexpand_file_name (filename, Qnil); 1391*60165Shibler if (access (XSTRING (abspath)->data, 0) >= 0) 1392*60165Shibler return (access (XSTRING (abspath)->data, 2) >= 0) ? Qt : Qnil; 1393*60165Shibler dir = Ffile_name_directory (abspath); 1394*60165Shibler #ifdef VMS 1395*60165Shibler if (!NULL (dir)) 1396*60165Shibler dir = Fdirectory_file_name (dir); 1397*60165Shibler #endif /* VMS */ 1398*60165Shibler return (access (!NULL (dir) ? (char *) XSTRING (dir)->data : "", 2) >= 0 1399*60165Shibler ? Qt : Qnil); 1400*60165Shibler } 1401*60165Shibler 1402*60165Shibler DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0, 1403*60165Shibler "Return t if file FILENAME is the name of a directory as a file.\n\ 1404*60165Shibler A directory name spec may be given instead; then the value is t\n\ 1405*60165Shibler if the directory so specified exists and really is a directory.") 1406*60165Shibler (filename) 1407*60165Shibler Lisp_Object filename; 1408*60165Shibler { 1409*60165Shibler register Lisp_Object abspath; 1410*60165Shibler struct stat st; 1411*60165Shibler 1412*60165Shibler abspath = expand_and_dir_to_file (filename, current_buffer->directory); 1413*60165Shibler 1414*60165Shibler if (stat (XSTRING (abspath)->data, &st) < 0) 1415*60165Shibler return Qnil; 1416*60165Shibler return (st.st_mode & S_IFMT) == S_IFDIR ? Qt : Qnil; 1417*60165Shibler } 1418*60165Shibler 1419*60165Shibler DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0, 1420*60165Shibler "Return mode bits of FILE, as an integer.") 1421*60165Shibler (filename) 1422*60165Shibler Lisp_Object filename; 1423*60165Shibler { 1424*60165Shibler Lisp_Object abspath; 1425*60165Shibler struct stat st; 1426*60165Shibler 1427*60165Shibler abspath = expand_and_dir_to_file (filename, current_buffer->directory); 1428*60165Shibler 1429*60165Shibler if (stat (XSTRING (abspath)->data, &st) < 0) 1430*60165Shibler return Qnil; 1431*60165Shibler return make_number (st.st_mode & 07777); 1432*60165Shibler } 1433*60165Shibler 1434*60165Shibler DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2, 0, 1435*60165Shibler "Set mode bits of FILE to MODE (an integer).\n\ 1436*60165Shibler Only the 12 low bits of MODE are used.") 1437*60165Shibler (filename, mode) 1438*60165Shibler Lisp_Object filename, mode; 1439*60165Shibler { 1440*60165Shibler Lisp_Object abspath; 1441*60165Shibler 1442*60165Shibler abspath = Fexpand_file_name (filename, current_buffer->directory); 1443*60165Shibler CHECK_NUMBER (mode, 1); 1444*60165Shibler 1445*60165Shibler #ifndef APOLLO 1446*60165Shibler if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0) 1447*60165Shibler report_file_error ("Doing chmod", Fcons (abspath, Qnil)); 1448*60165Shibler #else /* APOLLO */ 1449*60165Shibler if (!egetenv ("USE_DOMAIN_ACLS")) 1450*60165Shibler { 1451*60165Shibler struct stat st; 1452*60165Shibler struct timeval tvp[2]; 1453*60165Shibler 1454*60165Shibler /* chmod on apollo also change the file's modtime; need to save the 1455*60165Shibler modtime and then restore it. */ 1456*60165Shibler if (stat (XSTRING (abspath)->data, &st) < 0) 1457*60165Shibler { 1458*60165Shibler report_file_error ("Doing chmod", Fcons (abspath, Qnil)); 1459*60165Shibler return (Qnil); 1460*60165Shibler } 1461*60165Shibler 1462*60165Shibler if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0) 1463*60165Shibler report_file_error ("Doing chmod", Fcons (abspath, Qnil)); 1464*60165Shibler 1465*60165Shibler /* reset the old accessed and modified times. */ 1466*60165Shibler tvp[0].tv_sec = st.st_atime + 1; /* +1 due to an Apollo roundoff bug */ 1467*60165Shibler tvp[0].tv_usec = 0; 1468*60165Shibler tvp[1].tv_sec = st.st_mtime + 1; /* +1 due to an Apollo roundoff bug */ 1469*60165Shibler tvp[1].tv_usec = 0; 1470*60165Shibler 1471*60165Shibler if (utimes (XSTRING (abspath)->data, tvp) < 0) 1472*60165Shibler report_file_error ("Doing utimes", Fcons (abspath, Qnil)); 1473*60165Shibler } 1474*60165Shibler #endif /* APOLLO */ 1475*60165Shibler 1476*60165Shibler return Qnil; 1477*60165Shibler } 1478*60165Shibler 1479*60165Shibler DEFUN ("file-newer-than-file-p", Ffile_newer_than_file_p, Sfile_newer_than_file_p, 2, 2, 0, 1480*60165Shibler "Return t if file FILE1 is newer than file FILE2.\n\ 1481*60165Shibler If FILE1 does not exist, the answer is nil;\n\ 1482*60165Shibler otherwise, if FILE2 does not exist, the answer is t.") 1483*60165Shibler (file1, file2) 1484*60165Shibler Lisp_Object file1, file2; 1485*60165Shibler { 1486*60165Shibler Lisp_Object abspath; 1487*60165Shibler struct stat st; 1488*60165Shibler int mtime1; 1489*60165Shibler 1490*60165Shibler CHECK_STRING (file1, 0); 1491*60165Shibler CHECK_STRING (file2, 0); 1492*60165Shibler 1493*60165Shibler abspath = expand_and_dir_to_file (file1, current_buffer->directory); 1494*60165Shibler 1495*60165Shibler if (stat (XSTRING (abspath)->data, &st) < 0) 1496*60165Shibler return Qnil; 1497*60165Shibler 1498*60165Shibler mtime1 = st.st_mtime; 1499*60165Shibler 1500*60165Shibler abspath = expand_and_dir_to_file (file2, current_buffer->directory); 1501*60165Shibler 1502*60165Shibler if (stat (XSTRING (abspath)->data, &st) < 0) 1503*60165Shibler return Qt; 1504*60165Shibler 1505*60165Shibler return (mtime1 > st.st_mtime) ? Qt : Qnil; 1506*60165Shibler } 1507*60165Shibler 1508*60165Shibler close_file_unwind (fd) 1509*60165Shibler Lisp_Object fd; 1510*60165Shibler { 1511*60165Shibler close (XFASTINT (fd)); 1512*60165Shibler } 1513*60165Shibler 1514*60165Shibler DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents, 1515*60165Shibler 1, 2, 0, 1516*60165Shibler "Insert contents of file FILENAME after point.\n\ 1517*60165Shibler Returns list of absolute pathname and length of data inserted.\n\ 1518*60165Shibler If second argument VISIT is non-nil, the buffer's visited filename\n\ 1519*60165Shibler and last save file modtime are set, and it is marked unmodified.\n\ 1520*60165Shibler If visiting and the file does not exist, visiting is completed\n\ 1521*60165Shibler before the error is signaled.") 1522*60165Shibler (filename, visit) 1523*60165Shibler Lisp_Object filename, visit; 1524*60165Shibler { 1525*60165Shibler struct stat st; 1526*60165Shibler register int fd; 1527*60165Shibler register int inserted = 0; 1528*60165Shibler register int i = 0; 1529*60165Shibler int count = specpdl_ptr - specpdl; 1530*60165Shibler struct gcpro gcpro1; 1531*60165Shibler 1532*60165Shibler GCPRO1 (filename); 1533*60165Shibler if (!NULL (current_buffer->read_only)) 1534*60165Shibler Fbarf_if_buffer_read_only(); 1535*60165Shibler 1536*60165Shibler CHECK_STRING (filename, 0); 1537*60165Shibler filename = Fexpand_file_name (filename, Qnil); 1538*60165Shibler 1539*60165Shibler fd = -1; 1540*60165Shibler 1541*60165Shibler #ifndef APOLLO 1542*60165Shibler if (stat (XSTRING (filename)->data, &st) < 0 1543*60165Shibler || (fd = open (XSTRING (filename)->data, 0)) < 0) 1544*60165Shibler #else 1545*60165Shibler if ((fd = open (XSTRING (filename)->data, 0)) < 0 1546*60165Shibler || fstat (fd, &st) < 0) 1547*60165Shibler #endif /* not APOLLO */ 1548*60165Shibler { 1549*60165Shibler if (fd >= 0) close (fd); 1550*60165Shibler if (NULL (visit)) 1551*60165Shibler report_file_error ("Opening input file", Fcons (filename, Qnil)); 1552*60165Shibler st.st_mtime = -1; 1553*60165Shibler goto notfound; 1554*60165Shibler } 1555*60165Shibler 1556*60165Shibler record_unwind_protect (close_file_unwind, make_number (fd)); 1557*60165Shibler 1558*60165Shibler /* Supposedly happens on VMS. */ 1559*60165Shibler if (st.st_size < 0) 1560*60165Shibler error ("File size is negative"); 1561*60165Shibler { 1562*60165Shibler register Lisp_Object temp; 1563*60165Shibler 1564*60165Shibler /* Make sure point-max won't overflow after this insertion. */ 1565*60165Shibler XSET (temp, Lisp_Int, st.st_size + Z); 1566*60165Shibler if (st.st_size + Z != XINT (temp)) 1567*60165Shibler error ("maximum buffer size exceeded"); 1568*60165Shibler } 1569*60165Shibler 1570*60165Shibler if (NULL (visit)) 1571*60165Shibler prepare_to_modify_buffer (); 1572*60165Shibler 1573*60165Shibler move_gap (point); 1574*60165Shibler if (GAP_SIZE < st.st_size) 1575*60165Shibler make_gap (st.st_size - GAP_SIZE); 1576*60165Shibler 1577*60165Shibler while (1) 1578*60165Shibler { 1579*60165Shibler int try = min (st.st_size - inserted, 64 << 10); 1580*60165Shibler int this = read (fd, &FETCH_CHAR (point + inserted - 1) + 1, try); 1581*60165Shibler 1582*60165Shibler if (this <= 0) 1583*60165Shibler { 1584*60165Shibler i = this; 1585*60165Shibler break; 1586*60165Shibler } 1587*60165Shibler 1588*60165Shibler GPT += this; 1589*60165Shibler GAP_SIZE -= this; 1590*60165Shibler ZV += this; 1591*60165Shibler Z += this; 1592*60165Shibler inserted += this; 1593*60165Shibler } 1594*60165Shibler 1595*60165Shibler if (inserted > 0) 1596*60165Shibler MODIFF++; 1597*60165Shibler record_insert (point, inserted); 1598*60165Shibler 1599*60165Shibler close (fd); 1600*60165Shibler 1601*60165Shibler /* Discard the unwind protect */ 1602*60165Shibler specpdl_ptr = specpdl + count; 1603*60165Shibler 1604*60165Shibler if (i < 0) 1605*60165Shibler error ("IO error reading %s: %s", 1606*60165Shibler XSTRING (filename)->data, err_str (errno)); 1607*60165Shibler 1608*60165Shibler notfound: 1609*60165Shibler 1610*60165Shibler if (!NULL (visit)) 1611*60165Shibler { 1612*60165Shibler current_buffer->undo_list = Qnil; 1613*60165Shibler #ifdef APOLLO 1614*60165Shibler stat (XSTRING (filename)->data, &st); 1615*60165Shibler #endif 1616*60165Shibler current_buffer->modtime = st.st_mtime; 1617*60165Shibler current_buffer->save_modified = MODIFF; 1618*60165Shibler current_buffer->auto_save_modified = MODIFF; 1619*60165Shibler XFASTINT (current_buffer->save_length) = Z - BEG; 1620*60165Shibler #ifdef CLASH_DETECTION 1621*60165Shibler if (!NULL (current_buffer->filename)) 1622*60165Shibler unlock_file (current_buffer->filename); 1623*60165Shibler unlock_file (filename); 1624*60165Shibler #endif /* CLASH_DETECTION */ 1625*60165Shibler current_buffer->filename = filename; 1626*60165Shibler /* If visiting nonexistent file, return nil. */ 1627*60165Shibler if (st.st_mtime == -1) 1628*60165Shibler report_file_error ("Opening input file", Fcons (filename, Qnil)); 1629*60165Shibler } 1630*60165Shibler 1631*60165Shibler UNGCPRO; 1632*60165Shibler return Fcons (filename, Fcons (make_number (inserted), Qnil)); 1633*60165Shibler } 1634*60165Shibler 1635*60165Shibler DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 5, 1636*60165Shibler "r\nFWrite region to file: ", 1637*60165Shibler "Write current region into specified file.\n\ 1638*60165Shibler When called from a program, takes three arguments:\n\ 1639*60165Shibler START, END and FILENAME. START and END are buffer positions.\n\ 1640*60165Shibler Optional fourth argument APPEND if non-nil means\n\ 1641*60165Shibler append to existing file contents (if any).\n\ 1642*60165Shibler Optional fifth argument VISIT if t means\n\ 1643*60165Shibler set last-save-file-modtime of buffer to this file's modtime\n\ 1644*60165Shibler and mark buffer not modified.\n\ 1645*60165Shibler If VISIT is neither t nor nil, it means do not print\n\ 1646*60165Shibler the \"Wrote file\" message.") 1647*60165Shibler (start, end, filename, append, visit) 1648*60165Shibler Lisp_Object start, end, filename, append, visit; 1649*60165Shibler { 1650*60165Shibler register int desc; 1651*60165Shibler int failure; 1652*60165Shibler int save_errno; 1653*60165Shibler unsigned char *fn; 1654*60165Shibler struct stat st; 1655*60165Shibler int tem; 1656*60165Shibler int count = specpdl_ptr - specpdl; 1657*60165Shibler #ifdef VMS 1658*60165Shibler unsigned char *fname = 0; /* If non-0, original filename (must rename) */ 1659*60165Shibler #endif /* VMS */ 1660*60165Shibler 1661*60165Shibler /* Special kludge to simplify auto-saving */ 1662*60165Shibler if (NULL (start)) 1663*60165Shibler { 1664*60165Shibler XFASTINT (start) = BEG; 1665*60165Shibler XFASTINT (end) = Z; 1666*60165Shibler } 1667*60165Shibler else 1668*60165Shibler validate_region (&start, &end); 1669*60165Shibler 1670*60165Shibler filename = Fexpand_file_name (filename, Qnil); 1671*60165Shibler fn = XSTRING (filename)->data; 1672*60165Shibler 1673*60165Shibler #ifdef CLASH_DETECTION 1674*60165Shibler if (!auto_saving) 1675*60165Shibler lock_file (filename); 1676*60165Shibler #endif /* CLASH_DETECTION */ 1677*60165Shibler 1678*60165Shibler desc = -1; 1679*60165Shibler if (!NULL (append)) 1680*60165Shibler desc = open (fn, O_WRONLY); 1681*60165Shibler 1682*60165Shibler if (desc < 0) 1683*60165Shibler #ifdef VMS 1684*60165Shibler if (auto_saving) /* Overwrite any previous version of autosave file */ 1685*60165Shibler { 1686*60165Shibler vms_truncate (fn); /* if fn exists, truncate to zero length */ 1687*60165Shibler desc = open (fn, O_RDWR); 1688*60165Shibler if (desc < 0) 1689*60165Shibler desc = creat_copy_attrs (XTYPE (current_buffer->filename) == Lisp_String 1690*60165Shibler ? XSTRING (current_buffer->filename)->data : 0, 1691*60165Shibler fn); 1692*60165Shibler } 1693*60165Shibler else /* Write to temporary name and rename if no errors */ 1694*60165Shibler { 1695*60165Shibler Lisp_Object temp_name; 1696*60165Shibler temp_name = Ffile_name_directory (filename); 1697*60165Shibler 1698*60165Shibler if (!NULL (temp_name)) 1699*60165Shibler { 1700*60165Shibler temp_name = Fmake_temp_name (concat2 (temp_name, 1701*60165Shibler build_string ("$$SAVE$$"))); 1702*60165Shibler fname = XSTRING (filename)->data; 1703*60165Shibler fn = XSTRING (temp_name)->data; 1704*60165Shibler desc = creat_copy_attrs (fname, fn); 1705*60165Shibler if (desc < 0) 1706*60165Shibler { 1707*60165Shibler /* If we can't open the temporary file, try creating a new 1708*60165Shibler version of the original file. VMS "creat" creates a 1709*60165Shibler new version rather than truncating an existing file. */ 1710*60165Shibler fn = fname; 1711*60165Shibler fname = 0; 1712*60165Shibler desc = creat (fn, 0666); 1713*60165Shibler if (desc < 0) 1714*60165Shibler { 1715*60165Shibler /* We can't make a new version; 1716*60165Shibler try to truncate and rewrite existing version if any. */ 1717*60165Shibler vms_truncate (fn); 1718*60165Shibler desc = open (fn, O_RDWR); 1719*60165Shibler } 1720*60165Shibler } 1721*60165Shibler } 1722*60165Shibler else 1723*60165Shibler desc = creat (fn, 0666); 1724*60165Shibler } 1725*60165Shibler #else /* not VMS */ 1726*60165Shibler desc = creat (fn, 0666); 1727*60165Shibler #endif /* not VMS */ 1728*60165Shibler 1729*60165Shibler if (desc < 0) 1730*60165Shibler { 1731*60165Shibler #ifdef CLASH_DETECTION 1732*60165Shibler save_errno = errno; 1733*60165Shibler if (!auto_saving) unlock_file (filename); 1734*60165Shibler errno = save_errno; 1735*60165Shibler #endif /* CLASH_DETECTION */ 1736*60165Shibler report_file_error ("Opening output file", Fcons (filename, Qnil)); 1737*60165Shibler } 1738*60165Shibler 1739*60165Shibler record_unwind_protect (close_file_unwind, make_number (desc)); 1740*60165Shibler 1741*60165Shibler if (!NULL (append)) 1742*60165Shibler if (lseek (desc, 0, 2) < 0) 1743*60165Shibler { 1744*60165Shibler #ifdef CLASH_DETECTION 1745*60165Shibler if (!auto_saving) unlock_file (filename); 1746*60165Shibler #endif /* CLASH_DETECTION */ 1747*60165Shibler report_file_error ("Lseek error", Fcons (filename, Qnil)); 1748*60165Shibler } 1749*60165Shibler 1750*60165Shibler #ifdef VMS 1751*60165Shibler /* 1752*60165Shibler * Kludge Warning: The VMS C RTL likes to insert carriage returns 1753*60165Shibler * if we do writes that don't end with a carriage return. Furthermore 1754*60165Shibler * it cannot handle writes of more then 16K. The modified 1755*60165Shibler * version of "sys_write" in SYSDEP.C (see comment there) copes with 1756*60165Shibler * this EXCEPT for the last record (iff it doesn't end with a carriage 1757*60165Shibler * return). This implies that if your buffer doesn't end with a carriage 1758*60165Shibler * return, you get one free... tough. However it also means that if 1759*60165Shibler * we make two calls to sys_write (a la the following code) you can 1760*60165Shibler * get one at the gap as well. The easiest way to fix this (honest) 1761*60165Shibler * is to move the gap to the next newline (or the end of the buffer). 1762*60165Shibler * Thus this change. 1763*60165Shibler * 1764*60165Shibler * Yech! 1765*60165Shibler */ 1766*60165Shibler if (GPT > BEG && GPT_ADDR[-1] != '\n') 1767*60165Shibler move_gap (find_next_newline (GPT, 1)); 1768*60165Shibler #endif 1769*60165Shibler 1770*60165Shibler failure = 0; 1771*60165Shibler if (XINT (start) != XINT (end)) 1772*60165Shibler { 1773*60165Shibler if (XINT (start) < GPT) 1774*60165Shibler { 1775*60165Shibler register int end1 = XINT (end); 1776*60165Shibler tem = XINT (start); 1777*60165Shibler failure = 0 > e_write (desc, &FETCH_CHAR (tem), 1778*60165Shibler min (GPT, end1) - tem); 1779*60165Shibler save_errno = errno; 1780*60165Shibler } 1781*60165Shibler 1782*60165Shibler if (XINT (end) > GPT && !failure) 1783*60165Shibler { 1784*60165Shibler tem = XINT (start); 1785*60165Shibler tem = max (tem, GPT); 1786*60165Shibler failure = 0 > e_write (desc, &FETCH_CHAR (tem), XINT (end) - tem); 1787*60165Shibler save_errno = errno; 1788*60165Shibler } 1789*60165Shibler } 1790*60165Shibler 1791*60165Shibler #ifndef USG 1792*60165Shibler #ifndef VMS 1793*60165Shibler #ifndef BSD4_1 1794*60165Shibler #ifndef alliant /* trinkle@cs.purdue.edu says fsync can return EBUSY 1795*60165Shibler on alliant, for no visible reason. */ 1796*60165Shibler /* Note fsync appears to change the modtime on BSD4.2 (both vax and sun). 1797*60165Shibler Disk full in NFS may be reported here. */ 1798*60165Shibler if (fsync (desc) < 0) 1799*60165Shibler failure = 1, save_errno = errno; 1800*60165Shibler #endif 1801*60165Shibler #endif 1802*60165Shibler #endif 1803*60165Shibler #endif 1804*60165Shibler 1805*60165Shibler #if 0 1806*60165Shibler /* Spurious "file has changed on disk" warnings have been 1807*60165Shibler observed on Sun 3 as well. Maybe close changes the modtime 1808*60165Shibler with nfs as well. */ 1809*60165Shibler 1810*60165Shibler /* On VMS and APOLLO, must do the stat after the close 1811*60165Shibler since closing changes the modtime. */ 1812*60165Shibler #ifndef VMS 1813*60165Shibler #ifndef APOLLO 1814*60165Shibler /* Recall that #if defined does not work on VMS. */ 1815*60165Shibler #define FOO 1816*60165Shibler fstat (desc, &st); 1817*60165Shibler #endif 1818*60165Shibler #endif 1819*60165Shibler #endif /* 0 */ 1820*60165Shibler 1821*60165Shibler /* NFS can report a write failure now. */ 1822*60165Shibler if (close (desc) < 0) 1823*60165Shibler failure = 1, save_errno = errno; 1824*60165Shibler 1825*60165Shibler #ifdef VMS 1826*60165Shibler /* If we wrote to a temporary name and had no errors, rename to real name. */ 1827*60165Shibler if (fname) 1828*60165Shibler { 1829*60165Shibler if (!failure) 1830*60165Shibler failure = (rename (fn, fname) != 0), save_errno = errno; 1831*60165Shibler fn = fname; 1832*60165Shibler } 1833*60165Shibler #endif /* VMS */ 1834*60165Shibler 1835*60165Shibler #ifndef FOO 1836*60165Shibler stat (fn, &st); 1837*60165Shibler #endif 1838*60165Shibler /* Discard the unwind protect */ 1839*60165Shibler specpdl_ptr = specpdl + count; 1840*60165Shibler 1841*60165Shibler #ifdef CLASH_DETECTION 1842*60165Shibler if (!auto_saving) 1843*60165Shibler unlock_file (filename); 1844*60165Shibler #endif /* CLASH_DETECTION */ 1845*60165Shibler 1846*60165Shibler /* Do this before reporting IO error 1847*60165Shibler to avoid a "file has changed on disk" warning on 1848*60165Shibler next attempt to save. */ 1849*60165Shibler if (EQ (visit, Qt)) 1850*60165Shibler current_buffer->modtime = st.st_mtime; 1851*60165Shibler 1852*60165Shibler if (failure) 1853*60165Shibler error ("IO error writing %s: %s", fn, err_str (save_errno)); 1854*60165Shibler 1855*60165Shibler if (EQ (visit, Qt)) 1856*60165Shibler { 1857*60165Shibler current_buffer->save_modified = MODIFF; 1858*60165Shibler XFASTINT (current_buffer->save_length) = Z - BEG; 1859*60165Shibler current_buffer->filename = filename; 1860*60165Shibler } 1861*60165Shibler else if (!NULL (visit)) 1862*60165Shibler return Qnil; 1863*60165Shibler 1864*60165Shibler if (!auto_saving) 1865*60165Shibler message ("Wrote %s", fn); 1866*60165Shibler 1867*60165Shibler return Qnil; 1868*60165Shibler } 1869*60165Shibler 1870*60165Shibler int 1871*60165Shibler e_write (desc, addr, len) 1872*60165Shibler int desc; 1873*60165Shibler register char *addr; 1874*60165Shibler register int len; 1875*60165Shibler { 1876*60165Shibler char buf[16 * 1024]; 1877*60165Shibler register char *p, *end; 1878*60165Shibler 1879*60165Shibler if (!EQ (current_buffer->selective_display, Qt)) 1880*60165Shibler return write (desc, addr, len) - len; 1881*60165Shibler else 1882*60165Shibler { 1883*60165Shibler p = buf; 1884*60165Shibler end = p + sizeof buf; 1885*60165Shibler while (len--) 1886*60165Shibler { 1887*60165Shibler if (p == end) 1888*60165Shibler { 1889*60165Shibler if (write (desc, buf, sizeof buf) != sizeof buf) 1890*60165Shibler return -1; 1891*60165Shibler p = buf; 1892*60165Shibler } 1893*60165Shibler *p = *addr++; 1894*60165Shibler if (*p++ == '\015') 1895*60165Shibler p[-1] = '\n'; 1896*60165Shibler } 1897*60165Shibler if (p != buf) 1898*60165Shibler if (write (desc, buf, p - buf) != p - buf) 1899*60165Shibler return -1; 1900*60165Shibler } 1901*60165Shibler return 0; 1902*60165Shibler } 1903*60165Shibler 1904*60165Shibler DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime, 1905*60165Shibler Sverify_visited_file_modtime, 1, 1, 0, 1906*60165Shibler "Return t if last mod time of BUF's visited file matches what BUF records.\n\ 1907*60165Shibler This means that the file has not been changed since it was visited or saved.") 1908*60165Shibler (buf) 1909*60165Shibler Lisp_Object buf; 1910*60165Shibler { 1911*60165Shibler struct buffer *b; 1912*60165Shibler struct stat st; 1913*60165Shibler 1914*60165Shibler CHECK_BUFFER (buf, 0); 1915*60165Shibler b = XBUFFER (buf); 1916*60165Shibler 1917*60165Shibler if (XTYPE (b->filename) != Lisp_String) return Qt; 1918*60165Shibler if (b->modtime == 0) return Qt; 1919*60165Shibler 1920*60165Shibler if (stat (XSTRING (b->filename)->data, &st) < 0) 1921*60165Shibler { 1922*60165Shibler /* If the file doesn't exist now and didn't exist before, 1923*60165Shibler we say that it isn't modified, provided the error is a tame one. */ 1924*60165Shibler if (errno == ENOENT || errno == EACCES || errno == ENOTDIR) 1925*60165Shibler st.st_mtime = -1; 1926*60165Shibler else 1927*60165Shibler st.st_mtime = 0; 1928*60165Shibler } 1929*60165Shibler if (st.st_mtime == b->modtime 1930*60165Shibler /* If both are positive, accept them if they are off by one second. */ 1931*60165Shibler || (st.st_mtime > 0 && b->modtime > 0 1932*60165Shibler && (st.st_mtime == b->modtime + 1 1933*60165Shibler || st.st_mtime == b->modtime - 1))) 1934*60165Shibler return Qt; 1935*60165Shibler return Qnil; 1936*60165Shibler } 1937*60165Shibler 1938*60165Shibler DEFUN ("clear-visited-file-modtime", Fclear_visited_file_modtime, 1939*60165Shibler Sclear_visited_file_modtime, 0, 0, 0, 1940*60165Shibler "Clear out records of last mod time of visited file.\n\ 1941*60165Shibler Next attempt to save will certainly not complain of a discrepancy.") 1942*60165Shibler () 1943*60165Shibler { 1944*60165Shibler current_buffer->modtime = 0; 1945*60165Shibler return Qnil; 1946*60165Shibler } 1947*60165Shibler 1948*60165Shibler Lisp_Object 1949*60165Shibler auto_save_error () 1950*60165Shibler { 1951*60165Shibler unsigned char *name = XSTRING (current_buffer->name)->data; 1952*60165Shibler 1953*60165Shibler bell (); 1954*60165Shibler message ("Autosaving...error for %s", name); 1955*60165Shibler Fsleep_for (make_number (1)); 1956*60165Shibler message ("Autosaving...error!for %s", name); 1957*60165Shibler Fsleep_for (make_number (1)); 1958*60165Shibler message ("Autosaving...error for %s", name); 1959*60165Shibler Fsleep_for (make_number (1)); 1960*60165Shibler return Qnil; 1961*60165Shibler } 1962*60165Shibler 1963*60165Shibler Lisp_Object 1964*60165Shibler auto_save_1 () 1965*60165Shibler { 1966*60165Shibler return 1967*60165Shibler Fwrite_region (Qnil, Qnil, 1968*60165Shibler current_buffer->auto_save_file_name, 1969*60165Shibler Qnil, Qlambda); 1970*60165Shibler } 1971*60165Shibler 1972*60165Shibler DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 1, "", 1973*60165Shibler "Auto-save all buffers that need it.\n\ 1974*60165Shibler This is all buffers that have auto-saving enabled\n\ 1975*60165Shibler and are changed since last auto-saved.\n\ 1976*60165Shibler Auto-saving writes the buffer into a file\n\ 1977*60165Shibler so that your editing is not lost if the system crashes.\n\ 1978*60165Shibler This file is not the file you visited; that changes only when you save.\n\n\ 1979*60165Shibler Non-nil argument means do not print any message if successful.") 1980*60165Shibler (nomsg) 1981*60165Shibler Lisp_Object nomsg; 1982*60165Shibler { 1983*60165Shibler struct buffer *old = current_buffer, *b; 1984*60165Shibler Lisp_Object tail, buf; 1985*60165Shibler int auto_saved = 0; 1986*60165Shibler int tried = 0; 1987*60165Shibler char *omessage = echo_area_contents; 1988*60165Shibler /* No GCPRO needed, because (when it matters) all Lisp_Object variables 1989*60165Shibler point to non-strings reached from Vbuffer_alist. */ 1990*60165Shibler 1991*60165Shibler auto_saving = 1; 1992*60165Shibler if (minibuf_level) 1993*60165Shibler nomsg = Qt; 1994*60165Shibler 1995*60165Shibler for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons; 1996*60165Shibler tail = XCONS (tail)->cdr) 1997*60165Shibler { 1998*60165Shibler buf = XCONS (XCONS (tail)->car)->cdr; 1999*60165Shibler b = XBUFFER (buf); 2000*60165Shibler /* Check for auto save enabled 2001*60165Shibler and file changed since last auto save 2002*60165Shibler and file changed since last real save. */ 2003*60165Shibler if (XTYPE (b->auto_save_file_name) == Lisp_String 2004*60165Shibler && b->save_modified < BUF_MODIFF (b) 2005*60165Shibler && b->auto_save_modified < BUF_MODIFF (b)) 2006*60165Shibler { 2007*60165Shibler /* If we at least consider a buffer for auto-saving, 2008*60165Shibler don't try again for a suitable time. */ 2009*60165Shibler tried++; 2010*60165Shibler if ((XFASTINT (b->save_length) * 10 2011*60165Shibler > (BUF_Z (b) - BUF_BEG (b)) * 13) 2012*60165Shibler /* A short file is likely to change a large fraction; 2013*60165Shibler spare the user annoying messages. */ 2014*60165Shibler && XFASTINT (b->save_length) > 5000 2015*60165Shibler /* These messages are frequent and annoying for `*mail*'. */ 2016*60165Shibler && !EQ (b->filename, Qnil)) 2017*60165Shibler { 2018*60165Shibler /* It has shrunk too much; don't checkpoint. */ 2019*60165Shibler message ("Buffer %s has shrunk a lot; not autosaving it", 2020*60165Shibler XSTRING (b->name)->data); 2021*60165Shibler Fsleep_for (make_number (1)); 2022*60165Shibler continue; 2023*60165Shibler } 2024*60165Shibler set_buffer_internal (b); 2025*60165Shibler if (!auto_saved && NULL (nomsg)) 2026*60165Shibler message1 ("Auto-saving..."); 2027*60165Shibler internal_condition_case (auto_save_1, Qt, auto_save_error); 2028*60165Shibler auto_saved++; 2029*60165Shibler b->auto_save_modified = BUF_MODIFF (b); 2030*60165Shibler XFASTINT (current_buffer->save_length) = Z - BEG; 2031*60165Shibler set_buffer_internal (old); 2032*60165Shibler } 2033*60165Shibler } 2034*60165Shibler 2035*60165Shibler if (tried) 2036*60165Shibler record_auto_save (); 2037*60165Shibler 2038*60165Shibler if (auto_saved && NULL (nomsg)) 2039*60165Shibler message1 (omessage ? omessage : "Auto-saving...done"); 2040*60165Shibler 2041*60165Shibler auto_saving = 0; 2042*60165Shibler return Qnil; 2043*60165Shibler } 2044*60165Shibler 2045*60165Shibler DEFUN ("set-buffer-auto-saved", Fset_buffer_auto_saved, 2046*60165Shibler Sset_buffer_auto_saved, 0, 0, 0, 2047*60165Shibler "Mark current buffer as auto-saved with its current text.\n\ 2048*60165Shibler No auto-save file will be written until the buffer changes again.") 2049*60165Shibler () 2050*60165Shibler { 2051*60165Shibler current_buffer->auto_save_modified = MODIFF; 2052*60165Shibler XFASTINT (current_buffer->save_length) = Z - BEG; 2053*60165Shibler return Qnil; 2054*60165Shibler } 2055*60165Shibler 2056*60165Shibler DEFUN ("recent-auto-save-p", Frecent_auto_save_p, Srecent_auto_save_p, 2057*60165Shibler 0, 0, 0, 2058*60165Shibler "Return t if buffer has been auto-saved since last read in or saved.") 2059*60165Shibler () 2060*60165Shibler { 2061*60165Shibler return (current_buffer->save_modified < current_buffer->auto_save_modified) ? Qt : Qnil; 2062*60165Shibler } 2063*60165Shibler 2064*60165Shibler /* Reading and completing file names */ 2065*60165Shibler extern Lisp_Object Ffile_name_completion (), Ffile_name_all_completions (); 2066*60165Shibler 2067*60165Shibler DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_internal, 2068*60165Shibler 3, 3, 0, 2069*60165Shibler "Internal subroutine for read-file-name. Do not call this.") 2070*60165Shibler (string, dir, action) 2071*60165Shibler Lisp_Object string, dir, action; 2072*60165Shibler /* action is nil for complete, t for return list of completions, 2073*60165Shibler lambda for verify final value */ 2074*60165Shibler { 2075*60165Shibler Lisp_Object name, specdir, realdir, val; 2076*60165Shibler if (XSTRING (string)->size == 0) 2077*60165Shibler { 2078*60165Shibler name = string; 2079*60165Shibler realdir = dir; 2080*60165Shibler if (EQ (action, Qlambda)) 2081*60165Shibler return Qnil; 2082*60165Shibler } 2083*60165Shibler else 2084*60165Shibler { 2085*60165Shibler string = Fsubstitute_in_file_name (string); 2086*60165Shibler name = Ffile_name_nondirectory (string); 2087*60165Shibler realdir = Ffile_name_directory (string); 2088*60165Shibler if (NULL (realdir)) 2089*60165Shibler realdir = dir; 2090*60165Shibler else 2091*60165Shibler realdir = Fexpand_file_name (realdir, dir); 2092*60165Shibler } 2093*60165Shibler 2094*60165Shibler if (NULL (action)) 2095*60165Shibler { 2096*60165Shibler specdir = Ffile_name_directory (string); 2097*60165Shibler val = Ffile_name_completion (name, realdir); 2098*60165Shibler if (XTYPE (val) != Lisp_String) 2099*60165Shibler return (val); 2100*60165Shibler 2101*60165Shibler if (!NULL (specdir)) 2102*60165Shibler val = concat2 (specdir, val); 2103*60165Shibler #ifndef VMS 2104*60165Shibler { 2105*60165Shibler register unsigned char *old, *new; 2106*60165Shibler register int n; 2107*60165Shibler int osize, count; 2108*60165Shibler 2109*60165Shibler osize = XSTRING (val)->size; 2110*60165Shibler /* Quote "$" as "$$" to get it past substitute-in-file-name */ 2111*60165Shibler for (n = osize, count = 0, old = XSTRING (val)->data; n > 0; n--) 2112*60165Shibler if (*old++ == '$') count++; 2113*60165Shibler if (count > 0) 2114*60165Shibler { 2115*60165Shibler old = XSTRING (val)->data; 2116*60165Shibler val = Fmake_string (make_number (osize + count), make_number (0)); 2117*60165Shibler new = XSTRING (val)->data; 2118*60165Shibler for (n = osize; n > 0; n--) 2119*60165Shibler if (*old != '$') 2120*60165Shibler *new++ = *old++; 2121*60165Shibler else 2122*60165Shibler { 2123*60165Shibler *new++ = '$'; 2124*60165Shibler *new++ = '$'; 2125*60165Shibler old++; 2126*60165Shibler } 2127*60165Shibler } 2128*60165Shibler } 2129*60165Shibler #endif /* Not VMS */ 2130*60165Shibler return (val); 2131*60165Shibler } 2132*60165Shibler 2133*60165Shibler if (EQ (action, Qt)) 2134*60165Shibler return Ffile_name_all_completions (name, realdir); 2135*60165Shibler /* Only other case actually used is ACTION = lambda */ 2136*60165Shibler #ifdef VMS 2137*60165Shibler /* Supposedly this helps commands such as `cd' that read directory names, 2138*60165Shibler but can someone explain how it helps them? -- RMS */ 2139*60165Shibler if (XSTRING (name)->size == 0) 2140*60165Shibler return Qt; 2141*60165Shibler #endif /* VMS */ 2142*60165Shibler return Ffile_exists_p (string); 2143*60165Shibler } 2144*60165Shibler 2145*60165Shibler DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 4, 0, 2146*60165Shibler "Read file name, prompting with PROMPT and completing in directory DIR.\n\ 2147*60165Shibler Value is not expanded! You must call expand-file-name yourself.\n\ 2148*60165Shibler Default name to DEFAULT if user enters a null string.\n\ 2149*60165Shibler Fourth arg MUSTMATCH non-nil means require existing file's name.\n\ 2150*60165Shibler Non-nil and non-t means also require confirmation after completion.\n\ 2151*60165Shibler DIR defaults to current buffer's directory default.") 2152*60165Shibler (prompt, dir, defalt, mustmatch) 2153*60165Shibler Lisp_Object prompt, dir, defalt, mustmatch; 2154*60165Shibler { 2155*60165Shibler Lisp_Object val, insdef, tem; 2156*60165Shibler struct gcpro gcpro1, gcpro2; 2157*60165Shibler register char *homedir; 2158*60165Shibler int count; 2159*60165Shibler 2160*60165Shibler if (NULL (dir)) 2161*60165Shibler dir = current_buffer->directory; 2162*60165Shibler if (NULL (defalt)) 2163*60165Shibler defalt = current_buffer->filename; 2164*60165Shibler 2165*60165Shibler /* If dir starts with user's homedir, change that to ~. */ 2166*60165Shibler homedir = (char *) egetenv ("HOME"); 2167*60165Shibler if (homedir != 0 2168*60165Shibler && XTYPE (dir) == Lisp_String 2169*60165Shibler && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir)) 2170*60165Shibler && XSTRING (dir)->data[strlen (homedir)] == '/') 2171*60165Shibler { 2172*60165Shibler dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1, 2173*60165Shibler XSTRING (dir)->size - strlen (homedir) + 1); 2174*60165Shibler XSTRING (dir)->data[0] = '~'; 2175*60165Shibler } 2176*60165Shibler 2177*60165Shibler if (insert_default_directory) 2178*60165Shibler insdef = dir; 2179*60165Shibler else 2180*60165Shibler insdef = build_string (""); 2181*60165Shibler 2182*60165Shibler #ifdef VMS 2183*60165Shibler count = specpdl_ptr - specpdl; 2184*60165Shibler specbind (intern ("completion-ignore-case"), Qt); 2185*60165Shibler #endif 2186*60165Shibler 2187*60165Shibler GCPRO2 (insdef, defalt); 2188*60165Shibler val = Fcompleting_read (prompt, intern ("read-file-name-internal"), 2189*60165Shibler dir, mustmatch, 2190*60165Shibler insert_default_directory ? insdef : Qnil); 2191*60165Shibler 2192*60165Shibler #ifdef VMS 2193*60165Shibler unbind_to (count); 2194*60165Shibler #endif 2195*60165Shibler 2196*60165Shibler UNGCPRO; 2197*60165Shibler if (NULL (val)) 2198*60165Shibler error ("No file name specified"); 2199*60165Shibler tem = Fstring_equal (val, insdef); 2200*60165Shibler if (!NULL (tem) && !NULL (defalt)) 2201*60165Shibler return defalt; 2202*60165Shibler return Fsubstitute_in_file_name (val); 2203*60165Shibler } 2204*60165Shibler 2205*60165Shibler syms_of_fileio () 2206*60165Shibler { 2207*60165Shibler Qfile_error = intern ("file-error"); 2208*60165Shibler staticpro (&Qfile_error); 2209*60165Shibler Qfile_already_exists = intern("file-already-exists"); 2210*60165Shibler staticpro (&Qfile_already_exists); 2211*60165Shibler 2212*60165Shibler Fput (Qfile_error, Qerror_conditions, 2213*60165Shibler Fcons (Qfile_error, Fcons (Qerror, Qnil))); 2214*60165Shibler Fput (Qfile_error, Qerror_message, 2215*60165Shibler build_string ("File error")); 2216*60165Shibler 2217*60165Shibler Fput (Qfile_already_exists, Qerror_conditions, 2218*60165Shibler Fcons (Qfile_already_exists, 2219*60165Shibler Fcons (Qfile_error, Fcons (Qerror, Qnil)))); 2220*60165Shibler Fput (Qfile_already_exists, Qerror_message, 2221*60165Shibler build_string ("File already exists")); 2222*60165Shibler 2223*60165Shibler DEFVAR_BOOL ("insert-default-directory", &insert_default_directory, 2224*60165Shibler "*Non-nil means when reading a filename start with default dir in minibuffer."); 2225*60165Shibler insert_default_directory = 1; 2226*60165Shibler 2227*60165Shibler DEFVAR_BOOL ("vms-stmlf-recfm", &vms_stmlf_recfm, 2228*60165Shibler "*Non-nil means write new files with record format `stmlf'.\n\ 2229*60165Shibler nil means use format `var'. This variable is meaningful only on VMS."); 2230*60165Shibler vms_stmlf_recfm = 0; 2231*60165Shibler 2232*60165Shibler defsubr (&Sfile_name_directory); 2233*60165Shibler defsubr (&Sfile_name_nondirectory); 2234*60165Shibler defsubr (&Sfile_name_as_directory); 2235*60165Shibler defsubr (&Sdirectory_file_name); 2236*60165Shibler defsubr (&Smake_temp_name); 2237*60165Shibler defsubr (&Sexpand_file_name); 2238*60165Shibler defsubr (&Ssubstitute_in_file_name); 2239*60165Shibler defsubr (&Scopy_file); 2240*60165Shibler defsubr (&Sdelete_file); 2241*60165Shibler defsubr (&Srename_file); 2242*60165Shibler defsubr (&Sadd_name_to_file); 2243*60165Shibler #ifdef S_IFLNK 2244*60165Shibler defsubr (&Smake_symbolic_link); 2245*60165Shibler #endif /* S_IFLNK */ 2246*60165Shibler #ifdef VMS 2247*60165Shibler defsubr (&Sdefine_logical_name); 2248*60165Shibler #endif /* VMS */ 2249*60165Shibler #ifdef HPUX_NET 2250*60165Shibler defsubr (&Ssysnetunam); 2251*60165Shibler #endif /* HPUX_NET */ 2252*60165Shibler defsubr (&Sfile_name_absolute_p); 2253*60165Shibler defsubr (&Sfile_exists_p); 2254*60165Shibler defsubr (&Sfile_readable_p); 2255*60165Shibler defsubr (&Sfile_writable_p); 2256*60165Shibler defsubr (&Sfile_symlink_p); 2257*60165Shibler defsubr (&Sfile_directory_p); 2258*60165Shibler defsubr (&Sfile_modes); 2259*60165Shibler defsubr (&Sset_file_modes); 2260*60165Shibler defsubr (&Sfile_newer_than_file_p); 2261*60165Shibler defsubr (&Sinsert_file_contents); 2262*60165Shibler defsubr (&Swrite_region); 2263*60165Shibler defsubr (&Sverify_visited_file_modtime); 2264*60165Shibler defsubr (&Sclear_visited_file_modtime); 2265*60165Shibler defsubr (&Sdo_auto_save); 2266*60165Shibler defsubr (&Sset_buffer_auto_saved); 2267*60165Shibler defsubr (&Srecent_auto_save_p); 2268*60165Shibler 2269*60165Shibler defsubr (&Sread_file_name_internal); 2270*60165Shibler defsubr (&Sread_file_name); 2271*60165Shibler } 2272