"Fossies" - the Fresh Open Source Software Archive

Member "jed-0.99-19/src/file.c" (14 Dec 2009, 37988 Bytes) of package /linux/misc/jed-0.99-19.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "file.c" see the Fossies "Dox" file reference documentation.

    1 /* -*- mode: C; mode: fold; -*- */
    2 /* Copyright (c) 1992, 1998, 2000, 2002, 2003, 2004, 2005, 2006 John E. Davis
    3  * This file is part of JED editor library source.
    4  *
    5  * You may distribute this file under the terms the GNU General Public
    6  * License.  See the file COPYING for more information.
    7  */
    8 #include "config.h"
    9 #include "jed-feat.h"
   10 
   11 /*{{{ system include files */
   12 
   13 #ifdef __WIN32__
   14 /* This needs to go first before stdio is included. */
   15 # include <windows.h>
   16 # include <fcntl.h>
   17 # include <io.h>
   18 # include <sys/stat.h>
   19 #endif
   20 
   21 #ifdef __IBMC__
   22 #if SLANG_VERSION < 10308
   23 # define sleep(x) sys_pause(1000 * (x))
   24 #else
   25 /* sleep added to slang 10308 */
   26 extern unsigned int sleep (unsigned int);
   27 #endif
   28 #endif
   29 
   30 #include <stdio.h>
   31 #include <slang.h>
   32 
   33 #include "jdmacros.h"
   34 
   35 #include <string.h>
   36 #include <limits.h>
   37 
   38 #ifdef HAVE_STDLIB_H
   39 # include <stdlib.h>
   40 #endif
   41 
   42 #ifdef HAVE_UNISTD_H
   43 # include <unistd.h>
   44 #endif
   45 
   46 #ifdef __unix__
   47 # include <sys/types.h>
   48 # include <sys/stat.h>
   49 # include <sys/file.h>
   50 #endif
   51 
   52 #ifdef HAVE_UTIME
   53 # include <utime.h>
   54 #endif
   55 
   56 #ifdef HAVE_FCNTL_H
   57 # include <fcntl.h>
   58 #endif
   59 
   60 #ifdef HAVE_SYS_FCNTL_H
   61 # include <sys/fcntl.h>
   62 #endif
   63 
   64 #ifdef __os2__
   65 #include <fcntl.h>
   66 #include <io.h>
   67 #include <sys/types.h>
   68 #include <sys/stat.h>
   69  
   70  typedef struct HOLDFEA *PHOLDFEA;
   71  PHOLDFEA QueryEAs (char *name);
   72  int WriteEAs (char *name, PHOLDFEA pHoldFEA);
   73 #endif
   74 
   75 #ifdef __MSDOS__
   76 #include <fcntl.h>
   77 #include <io.h>
   78 #include <sys/stat.h>
   79 #endif
   80 
   81 #if defined(__DECC) && defined(VMS)
   82 # include <unixio.h>
   83 # include <unixlib.h>
   84 #endif
   85 
   86 #include <errno.h>
   87 #include <signal.h>
   88 
   89 #ifdef VMS
   90 # include <stat.h>
   91 # include <rms.h>
   92 #endif
   93 
   94 /* Was anything missed? */
   95 #ifndef O_RDONLY
   96 # ifdef VMS
   97 #  include <file.h>
   98 # else
   99 #  include <fcntl.h>
  100 # endif
  101 #endif
  102 
  103 #ifndef O_BINARY
  104 # define O_BINARY   0
  105 #endif
  106 
  107 /*}}}*/
  108 /*{{{ local inclue files */
  109 
  110 #include "buffer.h"
  111 #include "file.h"
  112 #include "misc.h"
  113 #include "sysdep.h"
  114 #include "paste.h"
  115 #include "ins.h"
  116 #include "ledit.h"
  117 #include "userinfo.h"
  118 #include "hooks.h"
  119 #include "screen.h"
  120 #include "sig.h"
  121 
  122 /*}}}*/
  123 
  124 #if defined (SIXTEEN_BIT_SYSTEM)
  125 #define MAX_LINE_LEN 1024
  126 #else
  127 #define MAX_LINE_LEN 64 * 1024
  128 #endif
  129 
  130 int Jed_Backup_By_Copying = 0;
  131 
  132 #ifdef VMS
  133 /*{{{ vms_stupid_open */
  134 
  135 static int vms_max_rec_size;
  136 static int VMS_write_rfm_fixed;
  137 int vms_stupid_open(char *file)
  138 {
  139    struct stat s;
  140    char rat_buf[80], rfm_buf[80], mrs_buf[40], *rfm = "var";
  141    unsigned short mode = 0, c;
  142    int ret;
  143 
  144    VMS_write_rfm_fixed = 0;
  145 
  146    strcpy(rfm_buf, "rfm=");
  147    
  148    
  149    if (0 == stat(file, &s))
  150      {
  151     strcpy(rat_buf, "rat");
  152     c = s.st_fab_rat;
  153     if (c & FAB$M_FTN)  strcat(rat_buf, ",ftn");
  154     if (c & FAB$M_CR)  strcat(rat_buf, ",cr");
  155     if (c & FAB$M_PRN)  strcat(rat_buf, ",prn");
  156     if (c & FAB$M_BLK)  strcat(rat_buf, ",blk");
  157     if (rat_buf[3] != 0) rat_buf[3] = '='; else *rat_buf = 0;
  158 
  159     c = s.st_fab_rfm;
  160     switch(c)
  161       {
  162        case FAB$C_UDF:  rfm = "udf"; break;
  163        case FAB$C_FIX:  
  164          rfm = "fix"; 
  165          if (s.st_fab_rat & (FAB$M_CR | FAB$M_CR))
  166            VMS_write_rfm_fixed = 1;
  167          break;
  168 
  169        case FAB$C_VAR:  rfm = "var"; break;
  170        case FAB$C_VFC:  rfm = "vfc"; break;
  171        case FAB$C_STM:  rfm = "stm"; break;
  172        case FAB$C_STMLF:  rfm = "stmlf"; break;
  173        case FAB$C_STMCR:  rfm = "stmcr"; break;
  174       }
  175     mode = s.st_mode & 0777;
  176      }
  177    else strcpy (rat_buf, "rat=cr");
  178    
  179    strcat(rfm_buf, rfm);
  180    
  181    if (vms_max_rec_size <= 0) vms_max_rec_size = 255;
  182    sprintf(mrs_buf, "mrs=%d", vms_max_rec_size);
  183       
  184    if (*rfm == 's')            /* stream */
  185      {
  186     ret = creat(file, mode, rfm_buf);
  187      }
  188    else
  189      {
  190     if (*rat_buf) ret = creat(file, mode, rfm_buf, mrs_buf, rat_buf);
  191     else ret = creat(file, mode, rfm_buf, mrs_buf);
  192      }
  193    if (ret >= 0) chmod(file, mode);
  194    return ret;
  195 }
  196 
  197 /*}}}*/
  198 #endif
  199 
  200 int Require_Final_Newline = 0;
  201 
  202 #define _JED_OPEN_READ          0
  203 #define _JED_OPEN_WRITE         1
  204 #define _JED_OPEN_APPEND        2
  205 #define _JED_OPEN_CREATE_EXCL       3
  206 
  207 /* 0 = read, 1 = write , 2 = append... */
  208 static int sys_open (char *file, int acces) /*{{{*/
  209 {
  210    int flags;
  211    unsigned int perms;
  212 #ifdef VMS
  213    char *p, neew[JED_MAX_PATH_LEN];
  214 #endif
  215 
  216    flags = file_status (file);
  217    if ((flags < 0) || (flags > 1)) 
  218      return -1;                /* directory? */
  219    
  220 #ifdef VMS
  221    /* on VMS I cheat since I do not want to deal with RMS at this point */
  222    VMS_write_rfm_fixed = 0;
  223    safe_strcpy(neew, file, sizeof (neew));
  224    p = neew; while (*p) if (*p == ';') *p = 0; else p++;
  225    
  226    switch (acces)
  227      {
  228       case _JED_OPEN_READ:
  229     return open(file, O_RDONLY, "ctx=rec","mbf=8","mbc=32","rop=RAH","shr=upi,get,put");
  230 
  231       case _JED_OPEN_WRITE:
  232       case _JED_OPEN_CREATE_EXCL:      /* FIXME */
  233     return vms_stupid_open (neew);
  234 
  235       case _JED_OPEN_APPEND:
  236     return open (file, O_WRONLY | O_APPEND | O_CREAT | O_BINARY);
  237       default:
  238     return -1;
  239      }
  240 
  241 #else
  242 
  243 # ifdef IBMPC_SYSTEM
  244    perms = S_IREAD | S_IWRITE;
  245 # else
  246    perms = 0666;
  247 # endif
  248 
  249    switch (acces)
  250      {
  251       case _JED_OPEN_READ:
  252     flags = O_RDONLY; 
  253     break;
  254       case _JED_OPEN_WRITE: 
  255     flags = O_WRONLY | O_CREAT | O_TRUNC;
  256     break;
  257       case _JED_OPEN_APPEND: 
  258     flags = O_WRONLY | O_CREAT | O_APPEND; 
  259     break;
  260       case _JED_OPEN_CREATE_EXCL:
  261     flags = O_WRONLY | O_CREAT | O_EXCL;
  262 #ifndef IBMPC_SYSTEM
  263     perms = 0600;
  264 #endif
  265     break;
  266     
  267       default:
  268     return -1;
  269      }
  270    
  271    flags |= O_BINARY;
  272    
  273    return open(file, flags, perms);
  274 #endif /* VMS */
  275 }
  276 
  277 /*}}}*/
  278 
  279 char *file_type (SLFUTURE_CONST char *file) /*{{{*/
  280 {
  281    char *p, *psave;
  282    
  283    if ((file == NULL)
  284        || (*file == 0))
  285      return NULL;
  286 
  287    file = extract_file(file);
  288    p = (char *) file; while (*p != 0) p++;
  289    psave = p;
  290    while((p != file) && (*p != '.')) p--;
  291    if (*p == '.') p++;
  292    if (p == file) return psave;
  293    return p;
  294 }
  295 
  296 /*}}}*/
  297 
  298 
  299 void jed_set_buffer_ctime (Buffer *b)
  300 {
  301    char *file;
  302 
  303    if ((b->file == NULL)
  304        || (b->file[0] == 0))
  305      {
  306     b->c_time = 0;
  307     return;
  308      }
  309 
  310    if (NULL == (file = SLang_concat_slstrings (b->dir, b->file)))
  311      {
  312     b->c_time = 0;
  313     return;
  314      }
  315    b->c_time = sys_file_mod_time (file);
  316    
  317    SLang_free_slstring (file);
  318 }
  319 
  320 #if (defined(__MSDOS__) || defined(__WIN32__)) && !defined(W_OK)
  321 # define W_OK 2
  322 # define F_OK 0
  323 #endif
  324 
  325 #ifdef __GO32__
  326 # define access i386_access
  327 #endif
  328 
  329 int jed_file_is_readonly (char *file, int respect_perms)
  330 {
  331    int ro = 0;
  332    struct stat st;
  333 
  334    if (respect_perms)
  335      {
  336     /* respect the file's permissions.  If any write permission bit is
  337      * is set, then consider it a writable candidate.
  338      */
  339 #if defined(S_IWGRP) && defined(S_IWOTH)
  340     if (0 == stat (file, &st))
  341       ro = (0 == (st.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)));
  342 #endif
  343      }
  344 
  345 #ifdef W_OK
  346    if (ro == 0)
  347      {
  348     if (0 == access(file, F_OK))
  349       {
  350          if (-1 == access(file, W_OK))
  351            ro = 1;
  352       }
  353     else
  354       {
  355          /* file does not exist.  Can we write to the directory? */
  356          char *dir;
  357          
  358          if (-1 == jed_dirfile_to_dir_file (file, &dir, NULL))
  359            return -1;
  360 
  361 # if defined(IBMPC_SYSTEM)
  362          /* knock of slash since some primitive systems cannot handle the 
  363           * final slash in a path name. 
  364           */
  365            {
  366           unsigned int len = strlen (dir);
  367           if (len > 3)   /* allow C:/, but not C:/xx/ */
  368             dir[len-1] = 0;
  369            }
  370 # endif
  371          if ((0 == access (dir, F_OK))
  372 # ifdef VMS
  373          && (-1 == access (dir, X_OK))
  374 #else
  375          && (-1 == access (dir, W_OK))
  376 #endif
  377         )
  378            ro = 1;
  379          
  380          SLfree (dir);
  381       }
  382      }
  383 #endif                     /* W_OK */
  384    return ro;
  385 }
  386 
  387 int jed_buffer_file_is_readonly (Buffer *b)
  388 {
  389    char *file;
  390    int ro;
  391 
  392    if ((b->file == NULL)
  393        || (b->file[0] == 0))
  394      return 0;
  395 
  396    file = jed_dir_file_merge (b->dir, b->file);
  397    if (file == NULL)
  398      return -1;
  399 
  400    ro = jed_file_is_readonly (file, 1);
  401 
  402    SLfree (file);
  403    return ro;
  404 }
  405 
  406 void set_file_modes (void) /*{{{*/
  407 {
  408    char *type;
  409 
  410    if (CBuf == NULL) return;
  411 
  412    jed_set_buffer_ctime (CBuf);
  413    if (1 == jed_buffer_file_is_readonly (CBuf))
  414      CBuf->flags |= READ_ONLY;
  415 
  416    type = NULL;
  417 
  418    if ((CBuf->file != NULL)
  419        && (CBuf->file[0] != 0))
  420      {
  421     CBuf->flags |= AUTO_SAVE_BUFFER;
  422     CBuf->hits = 0;
  423 
  424     if (type == NULL) 
  425       type = file_type (CBuf->file);
  426      }
  427 
  428    CBuf->modes = NO_MODE;
  429 #if JED_HAS_LINE_ATTRIBUTES
  430    CBuf->min_unparsed_line_num = 1;
  431    CBuf->max_unparsed_line_num = Max_LineNum + CBuf->nup;
  432 #endif
  433 
  434    if (type != NULL)
  435      {
  436     if (1 != jed_va_run_hooks ("_jed_set_mode_hooks", 
  437                    JED_HOOKS_RUN_UNTIL_NON_0, 1, type))
  438       (void) SLang_run_hooks("mode_hook", 1, type);
  439      }
  440 }
  441 
  442 /*}}}*/
  443 
  444 /*{{{ reading/inserting files */
  445 
  446 int read_file(char *file) /*{{{*/
  447 {
  448    int n, status;
  449 
  450    status = jed_va_run_hooks ("_jed_read_file_hooks", JED_HOOKS_RUN_UNTIL_NON_0, 1, file);
  451    if (status < 0)
  452      return -1;
  453    
  454    if (status > 0)
  455      /* FIXME!! Is this true?  What if no lines have been read. */
  456      n = Max_LineNum;
  457    else
  458      {
  459     int fp;
  460 
  461     if ((fp = sys_open(file, _JED_OPEN_READ)) < 0)
  462       {
  463          status = file_status(file);
  464          if (!status) return(-1);  /* file does not exist */
  465          return(-2); /* exists but not readable */
  466       }
  467     n = read_file_pointer(fp);
  468     close(fp);
  469      }
  470 
  471    eob();
  472    if ((Point < CLine->len)
  473        && ('\n' == *(CLine->data + Point)))
  474      make_line(2);
  475 
  476    VFile_Mode = VFILE_TEXT;
  477    return n;
  478 }
  479 
  480 /*}}}*/
  481 int insert_file_pointer(VFILE *vp) /*{{{*/
  482 {
  483    int n = 0;
  484    unsigned int num;
  485    unsigned char *vbuf;
  486    
  487    Suspend_Screen_Update = 1;
  488    while(NULL != (vbuf = (unsigned char *) vgets(vp, &num)))
  489      {
  490     n++;
  491     if (SLang_get_error ())
  492       break;
  493 
  494     if (-1 == jed_quick_insert (vbuf, (int) num))
  495       return -1;
  496      }
  497    return(n);
  498 }
  499 
  500 /*}}}*/
  501 int insert_file(char *file) /*{{{*/
  502 {
  503    VFILE *vp;
  504    int n;
  505    unsigned int un;
  506 
  507    un = Max_LineNum;
  508    if (1 == jed_va_run_hooks ("_jed_insert_file_hooks", JED_HOOKS_RUN_UNTIL_NON_0, 1, file))
  509      return (int) (Max_LineNum - un);
  510 
  511    if (NULL == (vp = vopen(file, 0, VFile_Mode))) return -1;
  512    n = insert_file_pointer(vp);
  513    vclose(vp);
  514    return(n);
  515 }
  516 
  517 /*}}}*/
  518 
  519 /*}}}*/
  520 
  521 /*{{{ writing to files */
  522 
  523 #ifdef __unix__
  524 # define BUFSIZE 0x10000
  525 #else
  526 #ifdef VMS
  527 # define BUFSIZE 0x3FFF
  528 #else 
  529 # define BUFSIZE 512
  530 #endif
  531 #endif
  532 
  533 static int Output_Buffer_Size = BUFSIZE;
  534 static char Output_Buffer[BUFSIZE];
  535 static char *Output_Bufferp;
  536 static char *Output_Bufferp_max;
  537 
  538 
  539 /* definitely perform the write.  Return number of chars written */
  540 static int jed_write1(int fd, char *b, unsigned int n) /*{{{*/
  541 {
  542 #if !defined(IBMPC_USE_ASM)
  543    int len;
  544    unsigned int total = 0;
  545 #ifdef VMS
  546    register char *bmax;
  547 #endif
  548    
  549    while (total < n)
  550      {
  551     int dlen;
  552     len = n - total;
  553 #ifdef VMS
  554     if (VMS_write_rfm_fixed)
  555       {
  556       }   
  557     /* VMS wants to terminate a record with a cr so adjust for this 
  558      * unfortunate fact.  The len - 1 stuff is so *bmax does not peek 
  559      * beyond its boundary.
  560      */
  561     bmax = b + (len - 1);
  562     while ((bmax > b) && (*bmax != '\n')) bmax--;
  563     if (bmax == b) bmax = b + (len - 1); /* cannot be helped */
  564     len = (int) (bmax - b) + 1;
  565 #endif
  566     while (-1 == (dlen = write (fd, b, len)))
  567       {
  568 #ifdef EINTR
  569          if (errno == EINTR)
  570            {
  571           if (0 == jed_handle_interrupt ())
  572             continue;
  573            }
  574 #endif
  575 #ifdef EAGAIN
  576          if (errno == EAGAIN)
  577            {
  578           if (0 == jed_handle_interrupt ())
  579             {
  580                jed_sleep (1);
  581                continue;
  582             }
  583            }
  584 #endif
  585 #ifdef ENOSPC
  586          if (errno == ENOSPC)
  587            {
  588           msg_error ("Write Failed: Disk Full.");
  589           return total;
  590            }
  591 #endif
  592          jed_verror ("Write Failed: (%d bytes attemped, errno = %d)", len, errno);
  593          return total;
  594       }
  595     
  596     total += (unsigned int) dlen;
  597     b += dlen;
  598      }
  599    return total;
  600 #else
  601    int num = -1;
  602    asm mov ah, 40h
  603    asm mov bx, fd
  604    asm mov cx, n
  605    asm push ds
  606    asm lds dx, dword ptr b
  607    asm int 21h
  608    asm pop ds
  609    asm jc L1
  610    asm mov num, ax             /* number of bytes written */
  611    L1: 
  612    return(num);
  613 #endif
  614 }
  615 
  616 /*}}}*/
  617 
  618 
  619 /* RMS wants to start a NEW record after a write so just forget it! */
  620 /* maybe do write-- return number of chars possibly written */
  621 static int jed_write(int fd, char *b, unsigned int n) /*{{{*/
  622 {
  623    int num, max, nl_flag = 0;
  624    unsigned int nsave = n;
  625    int cr_flag = CBuf->flags & ADD_CR_ON_WRITE_FLAG;
  626    
  627 #ifdef MAP_CR_TO_NL_FLAG
  628    if (CBuf->flags & MAP_CR_TO_NL_FLAG)
  629      {
  630     char *bmax = b + n;
  631     char *p, *pmax, ch;
  632     p = Output_Bufferp;
  633     pmax = Output_Bufferp_max;
  634     
  635     while (b < bmax)
  636       {
  637          ch = *b++;
  638          if ((ch == '\r') || (ch == '\n'))
  639            {
  640           if (cr_flag)
  641             {
  642                *p++ = ch;
  643                if (p == pmax)
  644              {
  645                 num = (int) (Output_Bufferp_max - Output_Bufferp);
  646                 if (num != jed_write1 (fd, Output_Bufferp, num))
  647                   return -1;
  648                 Output_Bufferp = Output_Buffer;
  649                 p = Output_Bufferp;
  650              }
  651             }
  652           *p++ = '\n';
  653            }
  654          else *p++ = ch;
  655          
  656          if (p == pmax)
  657            {
  658           num = (int) (Output_Bufferp_max - Output_Bufferp);
  659           if (num != jed_write1 (fd, Output_Buffer, num))
  660             return -1;
  661           Output_Bufferp = Output_Buffer;
  662           p = Output_Bufferp;
  663            }
  664       }
  665     Output_Bufferp = p;
  666     return nsave;
  667      }
  668 #endif        
  669    /* amount of space left in buffer */
  670    /* copy whats in b to the output buffer */
  671    while (n > 0)
  672      {
  673     num = (int) (Output_Bufferp_max - Output_Bufferp);
  674     if ((int) n > num)
  675       {
  676 #ifdef VMS
  677          max = (int) (Output_Bufferp - Output_Buffer);
  678          if (max)
  679            {
  680           if (max != jed_write1(fd, Output_Buffer, max))
  681             return(-1);
  682           Output_Bufferp = Output_Buffer;
  683           continue;
  684            }
  685 #endif        
  686          max = num;
  687          SLMEMCPY(Output_Bufferp, b, max);
  688          Output_Bufferp += max;
  689       }
  690 
  691     else if (cr_flag && 
  692          (*(b + (n - 1)) == '\n') && (VFile_Mode == VFILE_TEXT))
  693       {
  694          max = n - 1;
  695          SLMEMCPY(Output_Bufferp, b, max);
  696          Output_Bufferp += max;
  697          *Output_Bufferp++ = '\r';
  698          max++;
  699 
  700          /* can only write the \r */
  701          if (n == (unsigned int) num) nl_flag = 1; else *Output_Bufferp++ = '\n';
  702       }
  703     else
  704       {
  705          max = n;
  706          SLMEMCPY(Output_Bufferp, b, max);
  707          Output_Bufferp += max;
  708       }
  709     
  710     if (Output_Bufferp == Output_Bufferp_max)
  711       {
  712          Output_Bufferp = Output_Buffer;
  713          if (Output_Buffer_Size != jed_write1(fd, Output_Buffer, Output_Buffer_Size)) return(-1);
  714          if (nl_flag)
  715            {
  716           nl_flag = 0;
  717           *Output_Bufferp++ = '\n';
  718            }
  719       }
  720     b += max;
  721     n -= max;
  722      }
  723    return(nsave);
  724 }
  725 
  726 /*}}}*/
  727 
  728 /* returns -1 on failure */
  729 int write_region_to_fp (int fp) /*{{{*/
  730 {
  731    register int pnt, len;
  732    register Line *first, *last;
  733    int last_pnt, n = 0;
  734    char *err = "Write Failed!";
  735 
  736 #ifndef VMS
  737    char nl = '\n';
  738 #endif
  739    
  740    Output_Bufferp = Output_Buffer;
  741    Output_Bufferp_max = Output_Buffer + BUFSIZE;
  742    Output_Buffer_Size = BUFSIZE;
  743 
  744 #ifdef VMS
  745    if (VMS_write_rfm_fixed && (vms_max_rec_size <= BUFSIZE))
  746      {
  747     Output_Buffer_Size = vms_max_rec_size;
  748      }
  749    else VMS_write_rfm_fixed = 0;
  750 #endif   
  751    
  752    if (!check_region(&Number_One)) return(-1);
  753    last = CLine; last_pnt = Point;
  754 
  755    jed_pop_mark(1);
  756    first = CLine; pnt = Point;
  757 
  758    /* first should never be null without hitting last first.  If this
  759       ever happens, check_region failed. */
  760    while (first != last)
  761      {
  762     len = first->len - pnt;
  763     if (len != jed_write(fp, (char *) (first->data + pnt), len))
  764       {
  765          msg_error(err);
  766       }
  767     
  768     /* This goes here inside the loop because it is possible for external
  769        events to set error_buffer */
  770     pnt = 0;
  771     if (SLang_get_error ()) break;
  772     first = first->next;
  773     n++;
  774      }
  775 
  776    if (!SLang_get_error () && (last_pnt != 0))
  777      {
  778     len = last_pnt - pnt;
  779     if (len != jed_write(fp, (char *) (last->data + pnt), len))
  780       {
  781          msg_error(err);
  782       }
  783     n++;
  784      }
  785 #ifndef VMS
  786    if ((Require_Final_Newline) && (CBuf->end == last))
  787      {
  788     eob(); if (Point) jed_write(fp, &nl, 1);
  789      }
  790 #endif
  791    
  792 
  793    /* Now flush output buffer if necessary */
  794    
  795    len = (int) (Output_Bufferp - Output_Buffer);
  796    if (!SLang_get_error () && len) if (len != jed_write1(fp, Output_Buffer, len))
  797      {
  798     msg_error(err);
  799      }
  800    
  801    Output_Bufferp = Output_Buffer;
  802 
  803    
  804    pop_spot();
  805    VFile_Mode = VFILE_TEXT;
  806    if (SLang_get_error ()) return(-1);
  807    return(n);
  808 }
  809 
  810 /*}}}*/
  811 
  812 static int jed_close (int fp) /*{{{*/
  813 {
  814    while (-1 == close(fp))
  815      {
  816 #ifdef EINTR
  817 #ifndef IBMPC_SYSTEM
  818     if (errno == EINTR) 
  819       {
  820          if (-1 == jed_handle_interrupt ())
  821            {
  822           errno = 0;
  823           jed_sleep (1);
  824           continue;
  825            }
  826       }
  827 #endif
  828 #endif
  829     msg_error ("Error closing file.  File system may be full.");
  830     return -1;
  831      }
  832    return 0;
  833 }
  834 
  835 /*}}}*/
  836 
  837 static int write_region_internal (char *file, int omode) /*{{{*/
  838 {
  839    int fd;
  840    int n;
  841    unsigned int num_lines;
  842 
  843 #if JED_HAS_EMACS_LOCKING
  844    if (-1 == jed_lock_file (file))
  845      return -1;
  846 #endif
  847    if (!check_region(&Number_Zero)) 
  848      return -1;
  849    
  850    num_lines = jed_count_lines_in_region ();
  851 
  852    switch (omode)
  853      {
  854       case _JED_OPEN_WRITE:
  855       case _JED_OPEN_CREATE_EXCL:
  856     n = jed_va_run_hooks ("_jed_write_region_hooks",
  857                   JED_HOOKS_RUN_UNTIL_NON_0, 1, file);
  858     break;
  859     
  860       default:
  861     n = jed_va_run_hooks ("_jed_append_region_hooks",
  862                   JED_HOOKS_RUN_UNTIL_NON_0, 1, file);
  863     break;
  864      }
  865 
  866    if (n > 0)
  867      n = num_lines;
  868    else if (n < 0)
  869      n = -1;
  870    else if (n == 0)
  871      {
  872     if ((fd = sys_open(file, omode)) < 0)
  873       {
  874          jed_verror ("Unable to open %s for writing.", file);
  875          return -1;
  876       }
  877 
  878     n = write_region_to_fp (fd);
  879     if (n == -1)
  880       (void) jed_close (fd);
  881     else if (-1 == jed_close (fd))
  882       n = -1;
  883      }
  884    
  885 #if JED_HAS_EMACS_LOCKING
  886    if (n != -1) jed_unlock_file (file);
  887 #endif
  888    return n;
  889 }
  890 
  891 /*}}}*/
  892 
  893 int write_region (char *file)
  894 {
  895    return write_region_internal (file, _JED_OPEN_WRITE);
  896 }
  897 
  898 
  899 /* returns -1 on failure and number of lines on success */
  900 static int write_file_internal (char *file, int omode) /*{{{*/
  901 {
  902    Mark *m;
  903    int n;
  904    int fnl;
  905       
  906 #ifdef VMS
  907    register Line *l;
  908    register int len = 0, max = 0;
  909 #endif
  910    
  911    push_spot();
  912    
  913 #if JED_HAS_SAVE_NARROW
  914    jed_push_narrow ();
  915    jed_widen_whole_buffer (CBuf);
  916 #endif
  917    
  918 #ifdef VMS
  919    l = CBuf->beg;
  920    while (l != NULL)
  921      {
  922     len = l->len;
  923     if (len > max) max = len;
  924     l = l->next;
  925      }
  926    vms_max_rec_size = max;
  927 #endif
  928    
  929    bob();
  930    jed_push_mark();  m = CBuf->marks;
  931    eob();
  932    fnl = Require_Final_Newline;
  933    if (CBuf->flags & BINARY_FILE) 
  934      {
  935     VFile_Mode = VFILE_BINARY;
  936     Require_Final_Newline = 0;
  937 
  938 #ifdef VMS
  939     vms_max_rec_size = 512;
  940 #endif
  941      }
  942 
  943 
  944    n = write_region_internal (file, omode);
  945 
  946    Require_Final_Newline = fnl;
  947    VFile_Mode = VFILE_TEXT;
  948    if (m == CBuf->marks) jed_pop_mark(0);
  949    
  950 #if JED_HAS_SAVE_NARROW
  951    jed_pop_narrow ();
  952 #endif   
  953    
  954    pop_spot();
  955    return(n);
  956 }
  957 
  958 /*}}}*/
  959 
  960 int append_to_file(char *file) /*{{{*/
  961 {
  962    int status;
  963    
  964    status = write_region_internal (file, _JED_OPEN_APPEND);
  965    check_buffers();
  966    return status;
  967 }
  968 
  969 /*}}}*/
  970 
  971 /*}}}*/
  972 
  973 static int make_autosave_filename(char *save, unsigned int buflen, char *dir, char *file) /*{{{*/
  974 {
  975    char *s;
  976 
  977    if (*file == 0) return(0);
  978       
  979    
  980    if (1 == SLang_run_hooks ("make_autosave_filename", 2, dir, file))
  981      {
  982     if (SLang_pop_slstring(&s)) return(0);
  983     strncpy(save, s, buflen);
  984     save[buflen - 1] = 0;
  985     SLang_free_slstring (s);
  986      }
  987    else
  988      {
  989 #if defined(IBMPC_SYSTEM)
  990     SLsnprintf (save, buflen, "%s#%s", dir, file);
  991 #else
  992 # ifdef VMS
  993     SLsnprintf (save, buflen, "%s_$%s;1", dir, file);
  994 # else
  995     SLsnprintf (save, buflen, "%s#%s#", dir, file);
  996 # endif
  997 #endif
  998      }
  999    return 1;
 1000 }
 1001 
 1002 /*}}}*/
 1003 
 1004 #ifndef VMS
 1005 int jed_copy_file (char *from, char *to) /*{{{*/
 1006 {
 1007    mode_t mode;
 1008    uid_t uid;
 1009    gid_t gid;
 1010    FILE *fp0, *fp1;
 1011    char buf[0x7FFF];
 1012    unsigned int readlen;
 1013    int ret;
 1014    struct stat st;
 1015 #ifdef HAVE_UTIME
 1016    struct utimbuf ut;
 1017 #endif
 1018 
 1019    if (1 != sys_chmod (from, 0, &mode, &uid, &gid))
 1020      return -1;            /* from does not exist as regular file */
 1021    
 1022    /* Need file modification times so that they can be preserved. */
 1023    if (-1 == stat (from, &st))
 1024      return -1;
 1025    
 1026    fp0 = fopen (from, "rb");
 1027    if (fp0 == NULL) return -1;
 1028 
 1029 #ifdef REAL_UNIX_SYSTEM
 1030    (void) sys_delete_file (to);
 1031    /* Try to avoid a race condition (code derived from Colin Phipps <crp22@cam.ac.uk>. */
 1032    ret = sys_open (to, _JED_OPEN_CREATE_EXCL);
 1033    if (ret == -1)
 1034      {
 1035     (void) fclose (fp0);
 1036     return -1;
 1037      }
 1038    if (NULL == (fp1 = fdopen (ret, "wb")))
 1039      {
 1040     (void) close (ret);
 1041     (void) sys_delete_file (to);
 1042     /* Drop */
 1043      }
 1044 #else
 1045    fp1 = fopen (to, "wb");
 1046 #endif
 1047 
 1048    if (fp1 == NULL) 
 1049      {
 1050     (void) fclose (fp0);
 1051     return -1;
 1052      }
 1053    
 1054    (void) chmod (to, 0600);
 1055 
 1056    ret = 0;
 1057    do
 1058      {
 1059     readlen = fread (buf, 1, sizeof(buf), fp0);
 1060     if (readlen)
 1061       {
 1062          if (readlen != fwrite (buf, 1, readlen, fp1))
 1063            {
 1064           ret = -1;
 1065           break;
 1066            }
 1067       }
 1068      }
 1069    while (readlen == sizeof (buf));
 1070    
 1071    fclose (fp0);
 1072 
 1073    if (EOF == fclose (fp1))
 1074      {
 1075     ret = -1;
 1076      }
 1077    
 1078    (void) sys_chmod (to, 1, &mode, &uid, &gid);
 1079 
 1080 #ifdef HAVE_UTIME
 1081    /* Set file modification times */
 1082    ut.actime = st.st_atime;
 1083    ut.modtime = st.st_mtime;
 1084    (void) utime (to, &ut);
 1085 #endif
 1086 
 1087    return ret;
 1088 }
 1089 /*}}}*/
 1090 #endif                     /* NOT VMS */
 1091 
 1092 #ifndef VMS   
 1093 static int perform_backup (char *from, char *to, int try_force_rename) /*{{{*/
 1094 {
 1095    int ret = -1;
 1096    int use_copy = Jed_Backup_By_Copying;
 1097 #ifdef REAL_UNIX_SYSTEM
 1098    /* If the file has hardlinks, then backup by copying. */
 1099    struct stat st;
 1100    
 1101    if (0 == stat (from, &st))
 1102      {
 1103     if (st.st_nlink > 1)
 1104       use_copy = 1;
 1105      }
 1106 #endif
 1107 
 1108    if (try_force_rename
 1109        || (use_copy == 0))
 1110      {
 1111     (void) unlink(to);
 1112 #ifdef __WIN32__
 1113     /* Rename is broken on win32 */
 1114     ret = jed_win32_rename (from, to);
 1115 #else
 1116     ret = rename (from, to);
 1117 #endif
 1118      }
 1119 
 1120    if (ret == -1)
 1121      ret = jed_copy_file (from, to);
 1122 
 1123    return ret;
 1124 }
 1125 /*}}}*/
 1126 #endif
 1127 
 1128 unsigned long sys_file_mod_time(char *file) /*{{{*/
 1129 {
 1130    struct stat buf;
 1131    
 1132    if (stat(file, &buf) < 0) return 0;
 1133 
 1134    return (unsigned long) buf.st_mtime;
 1135 }
 1136 
 1137 /*}}}*/
 1138 
 1139 int write_file_with_backup(char *dirfile) /*{{{*/
 1140 {
 1141    char autosave_file[JED_MAX_PATH_LEN];
 1142    int n;
 1143    int do_mode;
 1144    uid_t uid;
 1145    gid_t gid;
 1146    mode_t mode;
 1147 #ifndef VMS
 1148    char *old = NULL;
 1149    int backup_went_ok;
 1150 #endif
 1151 #ifdef __os2__
 1152    PHOLDFEA EAs;
 1153 #endif
 1154    char *dir, *file;
 1155 
 1156    if (NULL == (dirfile = jed_expand_link (dirfile)))
 1157      return -1;
 1158 
 1159    if (-1 == jed_dirfile_to_dir_file (dirfile, &dir, &file))
 1160      {
 1161     SLfree (dirfile);
 1162     return -1;
 1163      }
 1164 
 1165    if (*file == 0)
 1166      {
 1167     SLfree (dir);
 1168     SLfree (dir);
 1169     SLfree (dirfile);
 1170     return -1;
 1171      }
 1172 
 1173    *autosave_file = 0;
 1174    if (CBuf->flags & AUTO_SAVE_BUFFER)
 1175      (void) make_autosave_filename(autosave_file, sizeof (autosave_file), dir, file);
 1176 
 1177    do_mode = sys_chmod(dirfile, 0, &mode, &uid, &gid);
 1178    if ((do_mode != 0) && (do_mode != 1)) 
 1179      {
 1180     SLfree (dir);
 1181     SLfree (file);
 1182     SLfree (dirfile);
 1183     return -1;
 1184      }
 1185 
 1186    /* IF do_mode == 0, then the file does not exist.  This means that 
 1187     * there is nothing to backup.  If do_mode == 1, the file is a regular
 1188     * file which we do want to backup.
 1189     */
 1190 
 1191 #ifndef VMS
 1192    
 1193 # ifdef __os2__
 1194    EAs = QueryEAs (dirfile);
 1195 # endif
 1196    
 1197    backup_went_ok = 0;
 1198    if (do_mode
 1199        && ((CBuf->flags & NO_BACKUP_FLAG) == 0)
 1200        && (1 == SLang_run_hooks("make_backup_filename", 2, dir, file)))
 1201      {
 1202     if ((0 == SLang_pop_slstring(&old))
 1203         && (*old != 0))
 1204       {
 1205          backup_went_ok = (0 == perform_backup (dirfile, old, 0));
 1206       }
 1207      }
 1208 #endif                     /* NOT VMS */
 1209 
 1210    n = write_file_internal (dirfile, _JED_OPEN_WRITE);
 1211    /* This is for NFS time problems.  Even if the write failed, modify the 
 1212     * buffer's ctime because otherwise what is on the disk (a partial file) 
 1213     * will appear newer than the buffer.
 1214     */
 1215    CBuf->c_time = sys_file_mod_time(dirfile);
 1216 
 1217    if (n != -1)
 1218      {
 1219     if (*autosave_file)
 1220       (void) sys_delete_file (autosave_file);
 1221 
 1222     if (do_mode) /* must be an existing file, so preserve mode */
 1223       {
 1224 #if defined(__MSDOS__)
 1225          /* Want the archive bit set since this is a new version */
 1226          mode |= 1 << 5;
 1227 #endif
 1228          sys_chmod (dirfile, 1, &mode, &uid, &gid);
 1229 #ifdef __os2__
 1230          WriteEAs (dirfile, EAs);
 1231 #endif
 1232       }
 1233     
 1234     /* Since we wrote the buffer to the file, it is not modified. */
 1235     if (CBuf == find_file_buffer (dirfile))
 1236       CBuf->flags &= ~FILE_MODIFIED;
 1237     
 1238     mark_buffer_modified (CBuf, 0, 1);
 1239      }
 1240 #ifndef VMS
 1241    /* error -- put it back */
 1242    else if (backup_went_ok) perform_backup (old, dirfile, 1);
 1243 
 1244    if (old != NULL) SLang_free_slstring (old);
 1245 #endif
 1246 
 1247 #ifdef REAL_UNIX_SYSTEM
 1248    (void) jed_get_inode_info (dirfile, &CBuf->device, &CBuf->inode);
 1249 #endif
 1250    SLfree (dir);
 1251    SLfree (file);
 1252    SLfree (dirfile);
 1253 
 1254    return(n);
 1255 }
 1256 
 1257 /*}}}*/
 1258 
 1259 void auto_save_buffer(Buffer *b) /*{{{*/
 1260 {
 1261    char tmp[JED_MAX_PATH_LEN];
 1262    Buffer *old_buf;
 1263    unsigned int vfm = VFile_Mode;
 1264    char *dir, *file;
 1265 
 1266    if (b == NULL) return;
 1267    b->hits = 0;
 1268    if ((0 == (b->flags & BUFFER_MODIFIED))
 1269        || (0 == (b->flags & (AUTO_SAVE_BUFFER | AUTO_SAVE_JUST_SAVE))))
 1270      return;
 1271 
 1272    if (b->canonical_dirfile == NULL)
 1273      return;
 1274 
 1275 #if !JED_HAS_SAVE_NARROW
 1276    if (b->narrow != NULL) return;
 1277 #endif
 1278 
 1279    if (-1 == jed_dirfile_to_dir_file (b->canonical_dirfile, &dir, &file))
 1280      return;
 1281 
 1282    old_buf = CBuf;
 1283    switch_to_buffer(b);
 1284    
 1285    if (b->flags & BINARY_FILE)  VFile_Mode = VFILE_BINARY; 
 1286    else VFile_Mode = VFILE_TEXT;
 1287 
 1288    if (b->flags & AUTO_SAVE_BUFFER)
 1289      {
 1290     if (make_autosave_filename(tmp, sizeof (tmp), dir, file))
 1291       {
 1292          flush_message("autosaving..."); 
 1293          (void) sys_delete_file(tmp);
 1294          (void) write_file_internal (tmp, _JED_OPEN_CREATE_EXCL);
 1295          message("autosaving...done");
 1296       }
 1297       }
 1298    else (void) write_file_with_backup(b->canonical_dirfile);
 1299 
 1300    SLfree (file);
 1301    SLfree (dir);
 1302    
 1303    switch_to_buffer(old_buf);
 1304    VFile_Mode = vfm;
 1305 }
 1306 
 1307 /*}}}*/
 1308 
 1309 void auto_save_all (void) /*{{{*/
 1310 {
 1311     Buffer *b;
 1312 
 1313    if (NULL == (b = CBuf)) return;
 1314    do
 1315      {
 1316     jed_widen_whole_buffer (b);
 1317     if (CBuf == NULL) return;
 1318     if (*b->file != 0) auto_save_buffer(b);
 1319     if (CBuf == NULL) return;
 1320 
 1321     b = b->next;
 1322      }
 1323    while (b != CBuf);
 1324 }
 1325 
 1326 /*}}}*/
 1327 
 1328 #ifdef REAL_UNIX_SYSTEM
 1329 /*{{{ symbolic link stuff */
 1330 
 1331 static int is_link(char *f, char *f1) /*{{{*/
 1332 {
 1333    struct stat s;
 1334    unsigned int l;
 1335    int is_dir = 0;
 1336    char work[JED_MAX_PATH_LEN];
 1337    
 1338    l = strlen(f);
 1339    if (l == 0) return 0;
 1340    l--;
 1341    if ((l > 1) && (f[l] == '/'))
 1342      {
 1343     safe_strcpy(work, f, sizeof (work));
 1344     is_dir = 1;
 1345     f = work;
 1346     f[l] = 0;
 1347      }
 1348    
 1349 
 1350    if (( lstat(f, &s) == -1 ) 
 1351        /* || ((s.st_mode & S_IFMT)  S_IFLNK)) */
 1352        || (((s.st_mode & S_IFMT) & S_IFLNK) == 0))
 1353      return(0);
 1354    
 1355    l = JED_MAX_PATH_LEN - 1;
 1356    if (is_dir)
 1357      {
 1358     /* This way, it will be expanded properly upon return */
 1359     *f1++ = '.'; *f1++ = '.'; *f1++ = '/';
 1360     l -= 4;                /* 1 for final slash */
 1361      }
 1362          
 1363    if (-1 == (int) (l = readlink(f, f1, l))) return 0;
 1364    if (is_dir) f1[l++] = '/';
 1365    f1[l] = 0;
 1366    
 1367    /* If the link is an absolute pathname (starts with /) then the 
 1368     * ../ prefix should not go there.
 1369     */
 1370    if (is_dir && (*f1 == '/'))
 1371      {
 1372     char ch;
 1373     
 1374     f = f1 - 3;
 1375     while (0 != (ch = *f1++))
 1376       *f++ = ch;
 1377     
 1378     *f = 0;
 1379      }
 1380 
 1381    return(1);
 1382 }
 1383 
 1384 /*}}}*/
 1385 
 1386 /*}}}*/
 1387 #endif
 1388 
 1389 
 1390 #ifdef REAL_UNIX_SYSTEM
 1391 static char *expand_link_2(char *f) /*{{{*/
 1392 {
 1393    char work[JED_MAX_PATH_LEN], lnk[JED_MAX_PATH_LEN];
 1394    char *d = jed_standardize_filename (f);
 1395    unsigned int max_num = 20;
 1396 
 1397    while ((d != NULL) && is_link(d, lnk))
 1398      {
 1399     char *w, *w1, ch;
 1400     
 1401     if (*lnk == '/')           /* absolute */
 1402       safe_strcpy (work, lnk, sizeof (work));
 1403     else
 1404       {
 1405          safe_strcpy (work, d, sizeof (work));
 1406          *(extract_file(work)) = 0;
 1407          safe_strcat (work, lnk, sizeof (work));
 1408       }
 1409 
 1410     /* Collapse multiple // since jed_standardize_filename_static will interpret them
 1411      * differently.
 1412      */
 1413     w = w1 = work;
 1414     while ((ch = *w1++) != 0)
 1415       {
 1416          *w++ = ch;
 1417          if (ch == '/') while (*w1 == '/') w1++;
 1418       }
 1419     *w = 0;
 1420     
 1421     SLfree (d);
 1422     max_num--;
 1423     if (max_num == 0)
 1424       {
 1425          jed_verror ("possible circular-link detected");
 1426          return NULL;
 1427       }
 1428     d = jed_standardize_filename(work);
 1429      }
 1430    
 1431    return (d);
 1432 }
 1433 /*}}}*/
 1434 #endif                     /* REAL_UNIX_SYSTEM */
 1435 
 1436 #ifdef REAL_UNIX_SYSTEM
 1437 static char *expand_link_1(char *f) /*{{{*/
 1438 {
 1439    char *d = SLmake_string (f);
 1440    
 1441    if (d == NULL)
 1442      return d;
 1443 
 1444    f = d;
 1445 
 1446    while (1)
 1447      {
 1448     char *new_d, *d1;
 1449     
 1450     if (*f == '/')
 1451       f++;
 1452 
 1453     while (*f && (*f != '/'))
 1454       f++;
 1455     
 1456     if (*f == 0)
 1457       break;
 1458     
 1459     *f++ = 0;
 1460 
 1461     new_d = expand_link_2 (d);
 1462     if (new_d == NULL)
 1463       {
 1464          SLfree (d);
 1465          return NULL;
 1466       }
 1467 
 1468     d1 = SLpath_dircat (new_d, f);
 1469     f = d1 + strlen (new_d);
 1470     SLfree (d);
 1471     SLfree (new_d);
 1472     if (d1 == NULL)
 1473       return NULL;
 1474     d = d1;
 1475      }
 1476    
 1477    /* Now get filename component */
 1478    f = expand_link_2 (d);
 1479    SLfree (d);
 1480    return f;
 1481 }
 1482 #endif                     /* REAL_UNIX_SYSTEM */
 1483 
 1484 /* Malloced string returned */
 1485 char *jed_expand_link (char *f)
 1486 {
 1487 #ifndef REAL_UNIX_SYSTEM
 1488    return jed_standardize_filename (f);
 1489 #else
 1490    char *f1, *f2;
 1491    unsigned int len;
 1492    
 1493    /* Look for, e.g., /usr/local//tmp/foo and extract /tmp/foo.
 1494     * Do this before attempting to expand a link since links could 
 1495     * contain such constructs where they have a different meaning.
 1496     * 
 1497     * Do this only if // occurs because ../ constructs should be preserved
 1498     * if a subdir is a link to another.  That is consider:
 1499     * 
 1500     *    /path/a/b/../c.txt
 1501     * 
 1502     * jed_standardize_filename will convert this to
 1503     *  
 1504     *    /path/a/c.txt
 1505     * 
 1506     * However, if b is a symlink to /tmp/a/b then we really want the file
 1507     * /tmp/a/c.txt.
 1508     */
 1509 #if 1   
 1510    len = strlen (f);
 1511    if (NULL == (f = SLmake_nstring (f, len)))
 1512      return NULL;
 1513    
 1514    f2 = f + len;
 1515    while (f2 > f)
 1516      {
 1517     if ((*f2-- == '/') && (*f2 == '/'))
 1518       {
 1519          f2++;
 1520          break;
 1521       }
 1522      }
 1523 #else
 1524    if (NULL == (f = jed_standardize_filename (f)))
 1525      return NULL;
 1526    f2 = f;
 1527 #endif
 1528 
 1529    if (NULL == (f1 = expand_link_1 (f2)))
 1530      {
 1531     SLfree (f);
 1532     return NULL;
 1533      }
 1534 
 1535    if (0 == strcmp (f, f1))
 1536      {
 1537     SLfree (f);
 1538     return f1;
 1539      }
 1540    SLfree (f);
 1541 
 1542    f = f1;
 1543    /* Keep expanding the link until nothing changes */
 1544    while (1)
 1545      {
 1546     if (NULL == (f1 = expand_link_1 (f)))
 1547       {
 1548          SLfree (f);
 1549          return NULL;
 1550       }
 1551 
 1552     if (0 == strcmp (f, f1))
 1553       {
 1554          SLfree (f1);
 1555          return f;
 1556       }
 1557     SLfree (f);
 1558     f = f1;
 1559      }
 1560 #endif
 1561 }
 1562 
 1563 
 1564 /*}}}*/
 1565 
 1566 void visit_file (char *dir, char *file) /*{{{*/
 1567 {
 1568 #ifdef VMS
 1569    char *ff;
 1570 
 1571    file = SLmake_string (file);
 1572    if (file == NULL)
 1573      return;
 1574 
 1575    ff = file; 
 1576    while (*ff) 
 1577      {
 1578     if (*ff == ';')
 1579       {
 1580          *ff = 0; 
 1581          break;
 1582       }
 1583     ff++;
 1584      }
 1585 #endif
 1586 
 1587    if (
 1588 #if JED_FILE_PRESERVE_CASE
 1589        strcmp(file, CBuf->file) || strcmp(dir, CBuf->dir)
 1590 #else
 1591        jed_case_strcmp (file, CBuf->file) || jed_case_strcmp (dir, CBuf->dir)
 1592 #endif
 1593        )
 1594      {
 1595     buffer_filename (CBuf, dir, file);
 1596      }
 1597    /* We have already taken care of this in write buffer function.
 1598     */
 1599    /* CBuf->c_time = sys_time(); */
 1600 
 1601    check_buffers();
 1602 }
 1603 
 1604 /*}}}*/
 1605 
 1606 char *jed_dir_file_merge(SLFUTURE_CONST char *dir, SLFUTURE_CONST char *file) /*{{{*/
 1607 /* 
 1608  * returns result of merging dir with file. If file is empty, dir is
 1609  * considered to be whole file.
 1610  */
 1611 {
 1612    char *dirfile;
 1613 
 1614    if ((file == NULL) || (*file == 0))
 1615      return jed_standardize_filename (dir);
 1616 
 1617    
 1618    dirfile = SLmalloc (strlen (dir) + strlen (file) + 2);
 1619    if (dirfile == NULL)
 1620      return NULL;
 1621    strcpy (dirfile, dir);
 1622    fixup_dir (dirfile);
 1623    strcat (dirfile, file);
 1624     
 1625    file = jed_standardize_filename (dirfile);
 1626    SLfree (dirfile);
 1627    return (char *) file;
 1628 }
 1629 
 1630 /*}}}*/
 1631 
 1632 
 1633 int file_status(SLFUTURE_CONST char *file) /*{{{*/
 1634 /*
 1635  *  Returns a coded integer about file.  If the file does not exist, 0 is
 1636  *  returned.  Meaning:
 1637  *
 1638  *     2 file is a directory
 1639  *     1 file exists
 1640  *     0 file does not exist.
 1641  *    -1 no access.
 1642  *    -2 path invalid
 1643  *    -3 unknown error
 1644  */
 1645 {
 1646    mode_t mode = 0;
 1647    uid_t uid;
 1648    gid_t gid;
 1649    return sys_chmod(file, 0, &mode, &uid, &gid);
 1650 }
 1651 
 1652 /*}}}*/
 1653 
 1654 /* Returns 0 if unchanged, 1 if changed, or -1 if it does not exist
 1655  * and buffer is unmodified.
 1656  * 
 1657  * What does it mean for the file to be changed on the disk if the buffer
 1658  * corresponds to a symlink?  That is, imagine editing foo.c which is a
 1659  * symlink to bar.c.  If bar.c changes, then foo.c shold be flagged as
 1660  * changed.  But, what if the link foo.c is changed such that it nolonger 
 1661  * points to bar.c?  Now the buffer foo.c is nolonger connected with 
 1662  * bar.c.
 1663  * 
 1664  * To handle both situations, do not use the dirfile field of the buffer
 1665  * structure, since that corresponds to bar.c and not the link foo.c.
 1666  * Since the file_changed_on_disk function uses stat and not lstat, if foo.c
 1667  * is a link to bar.c, then bar.c will be checked.
 1668  * 
 1669  * If the file has changed, be sure to update the buffers dirfile field and
 1670  * update the inode info.  If another buffer has the same inode info, then
 1671  * the user has shot himself in the foot by making foo.c a hardlink.
 1672  */
 1673 int file_changed_on_disk (Buffer *buf, char *dirfile) /*{{{*/
 1674 {
 1675    unsigned long t;
 1676 
 1677    /* If we are saving this to a different file, then skip the test --
 1678     * unless dirfile is a link.
 1679     */
 1680    if ((buf->canonical_dirfile != NULL) 
 1681 #if JED_FILE_PRESERVE_CASE
 1682        && (0 != strcmp (buf->canonical_dirfile, dirfile))
 1683 #else
 1684        && (0 != jed_case_strcmp (buf->canonical_dirfile, dirfile))
 1685 #endif
 1686        )
 1687      {
 1688 #ifdef REAL_UNIX_SYSTEM
 1689     struct stat s;
 1690 
 1691     if ((-1 == lstat(dirfile, &s))
 1692         || (0 == ((s.st_mode & S_IFMT) & S_IFLNK)))
 1693       return 0;
 1694 #else   
 1695     return 0;
 1696 #endif
 1697      }
 1698 
 1699 #ifdef REAL_UNIX_SYSTEM
 1700    /*
 1701     * The file may still have been changed via a rename operation.
 1702     * Update (or even invalidate) inode information since directories may have
 1703     * been renamed, etc...
 1704     */
 1705      {
 1706     int device, inode;
 1707     (void) jed_get_inode_info (dirfile, &device, &inode);
 1708     if ((buf->device != -1) && (buf->inode != -1))
 1709       {
 1710          if ((device != buf->device) || (inode != buf->inode))
 1711            buf->flags |= FILE_MODIFIED;
 1712       }
 1713     buf->device = device;
 1714     buf->inode = inode;
 1715      }
 1716 #endif
 1717 
 1718    t = sys_file_mod_time(dirfile);
 1719    if (t == 0)
 1720      {
 1721     /* File does not exist.  If the buffer has not been modified since
 1722      * the last save, then the file has changed on the disk.
 1723      */
 1724     if (buf->c_time == 0)
 1725       return 0;
 1726 
 1727     if (buf->flags & BUFFER_MODIFIED)
 1728       return 0;
 1729     return -1;             /* does not exist */
 1730      }
 1731 
 1732    if (t > buf->c_time)
 1733      {
 1734 #if 0  /* Commented out because if the file did not exist when the buffer was created
 1735     * then c_time will be 0.  But if t>0, then this would indicate that an
 1736     * external process created/modified the file.
 1737     */
 1738     
 1739     if (buf->c_time == 0)          /* new buffer, writing to existing file */
 1740       return 0;
 1741 #endif
 1742     return 1;
 1743      }
 1744 
 1745    return 0;
 1746 }
 1747 
 1748 /*}}}*/
 1749 int file_time_cmp(char *file1, char *file2) /*{{{*/
 1750 {
 1751    unsigned long t1, t2;
 1752    
 1753    t1 = sys_file_mod_time(file1);
 1754    t2 = sys_file_mod_time(file2);
 1755     /*These times are modification  times from 1970.  Hence, the bigger 
 1756      * number represents the more recent change.  Let '>' denote 
 1757      * 'more recent than'.  This function returns:
 1758      *     1:  file1 > file2
 1759      *     0:  file 1 == file2
 1760      *     -1: otherwise. 
 1761      *  So:
 1762      */
 1763    if (t1 == t2) return(0);
 1764    if (t1 > t2) return(1); 
 1765    return(-1);
 1766 }
 1767 
 1768 /*}}}*/
 1769 
 1770 void auto_save(void) /*{{{*/
 1771 {
 1772    auto_save_buffer(CBuf);
 1773 }
 1774 
 1775 /*}}}*/
 1776 
 1777 void check_buffer(Buffer *b) /*{{{*/
 1778 {
 1779    b->flags &= ~FILE_MODIFIED;
 1780    if (*b->file)
 1781      {
 1782     char *dirfile = jed_dir_file_merge (b->dir, b->file);
 1783 
 1784     if (file_changed_on_disk (b, dirfile))
 1785       b->flags |= FILE_MODIFIED;
 1786 
 1787     SLfree (dirfile);
 1788      }
 1789 }
 1790 
 1791 /*}}}*/
 1792 void check_buffers() /*{{{*/
 1793 {
 1794    Buffer *b = CBuf;
 1795    do
 1796      {
 1797     check_buffer(b);
 1798     b = b->next;
 1799      }
 1800    while (b != CBuf);
 1801 }
 1802 
 1803 /*}}}*/
 1804 
 1805 void set_file_trans(int *mode) /*{{{*/
 1806 {
 1807    if (*mode) VFile_Mode = VFILE_BINARY; else VFile_Mode = VFILE_TEXT;
 1808 }
 1809 
 1810 /*}}}*/
 1811 
 1812 int read_file_pointer(int fp) /*{{{*/
 1813 {
 1814    int n = 0;
 1815    unsigned int num;
 1816    unsigned char *vbuf;
 1817    VFILE *vp;
 1818 
 1819    if (SLang_get_error () || (vp = vstream(fp, MAX_LINE_LEN, VFile_Mode)) == NULL) return(-1);
 1820    
 1821    if (NULL != (vbuf = (unsigned char *) vgets(vp, &num)))
 1822      {
 1823     n++;
 1824 #ifdef KEEP_SPACE_INFO
 1825     if (CLine->space < num)
 1826 #endif
 1827       remake_line(CLine->len + num + 1);
 1828     
 1829     SLMEMCPY((char *) CLine->data, (char *) vbuf, (int) num);
 1830     CLine->len = num;
 1831    
 1832     while(NULL != (vbuf = (unsigned char *) vgets(vp, &num)))
 1833       {
 1834          n++;
 1835          if ((num == 1) && (*vbuf == '\n')) make_line(num); else make_line(num + 1);
 1836          SLMEMCPY((char *) CLine->data, (char *) vbuf, (int) num);
 1837          CLine->len = num;
 1838          if (SLang_get_error () || SLKeyBoard_Quit) break;
 1839       }
 1840     if (vp->cr_flag) CBuf->flags |= ADD_CR_ON_WRITE_FLAG;
 1841     else CBuf->flags &= ~ADD_CR_ON_WRITE_FLAG;
 1842      }
 1843    
 1844    if (vp->buf != NULL) SLfree(vp->buf);
 1845    SLfree ((char *)vp);
 1846    return n;
 1847 }
 1848 
 1849 /*}}}*/
 1850 
 1851 #ifdef REAL_UNIX_SYSTEM
 1852 
 1853 int jed_get_inode_info (char *dirfile, int *device, int *inode)
 1854 {
 1855    struct stat st;
 1856    
 1857    *inode = *device = -1;
 1858    if ((dirfile == NULL)
 1859        || (-1 == stat (dirfile, &st)))
 1860      return -1;
 1861    
 1862    *inode = st.st_ino;
 1863    *device = st.st_dev;
 1864 
 1865    return 0;
 1866 }
 1867 
 1868 #endif
 1869 
 1870 void jed_set_umask (int mask)
 1871 {
 1872 #ifdef REAL_UNIX_SYSTEM
 1873    static int default_umask;
 1874 #endif
 1875 
 1876    if (mask == 0) 
 1877      {
 1878 #ifdef REAL_UNIX_SYSTEM
 1879     if (default_umask != 0)
 1880       (void) umask (default_umask);
 1881 #endif
 1882      }
 1883    else
 1884      {
 1885 #ifdef REAL_UNIX_SYSTEM
 1886     int u;
 1887     
 1888     u = umask (mask & 07777);
 1889     if (default_umask == 0) default_umask = u;
 1890 #endif
 1891      }
 1892 }
 1893 
 1894 int jed_dirfile_to_dir_file (char *dirfile, char **dirp, char **filep)
 1895 {
 1896    char *dir, *file;
 1897    unsigned int len;
 1898 
 1899    if (dirfile == NULL)
 1900      return -1;
 1901 
 1902    file = extract_file (dirfile);
 1903    len = (unsigned int) (file - dirfile);
 1904    if (NULL == (dir = SLmake_nstring (dirfile, len)))
 1905      return -1;
 1906    
 1907    if (filep != NULL)
 1908      {
 1909     if (NULL == (file = SLmake_string (file)))
 1910       {
 1911          SLfree (dir);
 1912          return -1;
 1913       }
 1914     *filep = file;
 1915      }
 1916 
 1917    *dirp = dir;
 1918    return 0;
 1919 }
 1920 
 1921 
 1922 char *jed_get_canonical_pathname (char *file)
 1923 {
 1924    return jed_expand_link (file);
 1925 }
 1926