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