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