Annotation of 43BSDReno/contrib/emacs-18.55/src/fileio.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.