1 /* -*- mode: C; mode: fold; -*- */
2 /* Copyright (c) 1992, 1998 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 # if !defined(__MINGW32__) && !defined(__CYGWIN32__)
17 #  define sleep Sleep
18 # endif
19 # include <fcntl.h>
20 # include <io.h>
21 # include <sys/stat.h>
22 #endif
23 
24 #ifdef __IBMC__
25 #if SLANG_VERSION < 10308
26 # define sleep(x) sys_pause(1000 * (x))
27 #else
28 /* sleep added to slang 10308 */
29 extern unsigned int sleep (unsigned int);
30 #endif
31 #endif
32 
33 #include <stdio.h>
34 #include <slang.h>
35 
36 #include "jdmacros.h"
37 
38 #include <string.h>
39 #include <limits.h>
40 
41 #ifdef HAVE_STDLIB_H
42 # include <stdlib.h>
43 #endif
44 
45 #ifdef HAVE_UNISTD_H
46 # include <unistd.h>
47 #endif
48 
49 #ifdef __unix__
50 # include <sys/types.h>
51 # include <sys/stat.h>
52 # include <sys/file.h>
53 #endif
54 
55 #ifdef HAVE_UTIME
56 # include <utime.h>
57 #endif
58 
59 #ifdef HAVE_FCNTL_H
60 # include <fcntl.h>
61 #endif
62 
63 #ifdef HAVE_SYS_FCNTL_H
64 # include <sys/fcntl.h>
65 #endif
66 
67 #ifdef __os2__
68 #include <fcntl.h>
69 #include <io.h>
70 #include <sys/types.h>
71 #include <sys/stat.h>
72 
73  typedef struct HOLDFEA *PHOLDFEA;
74  PHOLDFEA QueryEAs (char *name);
75  int WriteEAs (char *name, PHOLDFEA pHoldFEA);
76 #endif
77 
78 #ifdef __MSDOS__
79 #include <fcntl.h>
80 #include <io.h>
81 #include <sys/stat.h>
82 #endif
83 
84 #if defined(__DECC) && defined(VMS)
85 # include <unixio.h>
86 # include <unixlib.h>
87 #endif
88 
89 #include <errno.h>
90 
91 /* Was anything missed? */
92 #ifndef O_RDONLY
93 #ifdef VMS
94 #include <file.h>
95 #else
96 #include <fcntl.h>
97 #endif
98 #endif
99 
100 
101 /*}}}*/
102 /*{{{ local inclue files */
103 
104 #include "buffer.h"
105 #include "file.h"
106 #include "misc.h"
107 #include "sysdep.h"
108 #include "paste.h"
109 #include "ins.h"
110 #include "ledit.h"
111 #include "kanji.h"
112 
113 /*}}}*/
114 
115 #if defined (SIXTEEN_BIT_SYSTEM)
116 #define MAX_LINE_LEN 1024
117 #else
118 #define MAX_LINE_LEN 64 * 1024
119 #endif
120 
121 int Jed_Backup_By_Copying = 0;
122 
123 #ifdef VMS
124 /*{{{ vms_stupid_open */
125 
126 static int vms_max_rec_size;
127 #include <stat.h>
128 #include <rms.h>
129 static int VMS_write_rfm_fixed;
vms_stupid_open(char * file)130 int vms_stupid_open(char *file)
131 {
132    struct stat s;
133    char rat_buf[80], rfm_buf[80], mrs_buf[40], *rfm = "var";
134    unsigned short mode = 0, c;
135    int ret;
136 
137    VMS_write_rfm_fixed = 0;
138 
139    strcpy(rfm_buf, "rfm=");
140 
141 
142    if (0 == stat(file, &s))
143      {
144 	strcpy(rat_buf, "rat");
145 	c = s.st_fab_rat;
146 	if (c & FAB$M_FTN)  strcat(rat_buf, ",ftn");
147 	if (c & FAB$M_CR)  strcat(rat_buf, ",cr");
148 	if (c & FAB$M_PRN)  strcat(rat_buf, ",prn");
149 	if (c & FAB$M_BLK)  strcat(rat_buf, ",blk");
150 	if (rat_buf[3] != 0) rat_buf[3] = '='; else *rat_buf = 0;
151 
152 	c = s.st_fab_rfm;
153 	switch(c)
154 	  {
155 	   case FAB$C_UDF:  rfm = "udf"; break;
156 	   case FAB$C_FIX:
157 	     rfm = "fix";
158 	     if (s.st_fab_rat & (FAB$M_CR | FAB$M_CR))
159 	       VMS_write_rfm_fixed = 1;
160 	     break;
161 
162 	   case FAB$C_VAR:  rfm = "var"; break;
163 	   case FAB$C_VFC:  rfm = "vfc"; break;
164 	   case FAB$C_STM:  rfm = "stm"; break;
165 	   case FAB$C_STMLF:  rfm = "stmlf"; break;
166 	   case FAB$C_STMCR:  rfm = "stmcr"; break;
167 	  }
168 	mode = s.st_mode & 0777;
169      }
170    else strcpy (rat_buf, "rat=cr");
171 
172    strcat(rfm_buf, rfm);
173 
174    if (vms_max_rec_size <= 0) vms_max_rec_size = 255;
175    sprintf(mrs_buf, "mrs=%d", vms_max_rec_size);
176 
177    if (*rfm == 's')		       /* stream */
178      {
179 	ret = creat(file, mode, rfm_buf);
180      }
181    else
182      {
183 	if (*rat_buf) ret = creat(file, mode, rfm_buf, mrs_buf, rat_buf);
184 	else ret = creat(file, mode, rfm_buf, mrs_buf);
185      }
186    if (ret >= 0) chmod(file, mode);
187    return ret;
188 }
189 
190 /*}}}*/
191 #endif
192 
193 int Require_Final_Newline = 0;
194 
195 /* 0 = read, 1 = write , 2 = append... */
sys_open(char * file,int acces)196 static int sys_open(char *file, int acces) /*{{{*/
197 {
198    int fp = -1;
199    int flags;
200    unsigned int mode;
201 #ifdef VMS
202    char *p, neew[JED_MAX_PATH_LEN];
203 #endif
204 
205 #ifdef O_BINARY
206 	mode = O_BINARY;
207 #else
208 	mode = 0;
209 #endif
210 
211    flags = file_status(file);
212    if ((flags < 0) || (flags > 1)) return(fp);
213 
214    /* on VMS I cheat since I do not want to deal with RMS at this point */
215 #ifdef VMS
216    VMS_write_rfm_fixed = 0;
217    strcpy(neew, file);
218    p = neew; while (*p) if (*p == ';') *p = 0; else p++;
219 
220    if (acces == 0) fp = open(file, O_RDONLY, "ctx=rec","mbf=8","mbc=32","rop=RAH","shr=upi,get,put");
221    else if (acces == 1)
222      {
223 	fp = vms_stupid_open(neew);
224      }
225 
226    else if (acces == 2) fp = open(file, O_WRONLY | O_APPEND | O_CREAT | mode);
227 #else
228 
229    switch(acces)
230      {
231       case 0: flags =  O_RDONLY;
232 	break;
233       case 1: flags =  O_WRONLY | O_CREAT | O_TRUNC;
234 	break;
235       case 2: flags =  O_WRONLY | O_CREAT | O_APPEND;
236 	break;
237       default: return(fp);
238      }
239 
240    flags |= mode;
241 
242 #if defined (IBMPC_SYSTEM)
243    fp = open(file, flags, S_IREAD | S_IWRITE);
244 #else
245    fp = open(file, flags, 0666);
246 #endif
247 #endif /* VMS */
248    return(fp);
249 }
250 
251 /*}}}*/
252 
file_type(char * file)253 char *file_type(char *file) /*{{{*/
254 {
255    char *p, *psave;
256    if ((file == (char *) NULL) || (*file == 0)) return( (char *) NULL);
257 
258    file = extract_file(file);
259    p = file; while (*p != 0) p++;
260    psave = p;
261    while((p != file) && (*p != '.')) p--;
262    if (*p == '.') p++;
263    if (p == file) return(psave); else return(p);
264 }
265 
266 /*}}}*/
267 
268 
jed_set_buffer_ctime(Buffer * b)269 void jed_set_buffer_ctime (Buffer *b)
270 {
271    char file[JED_MAX_PATH_LEN + 1];
272 
273    if ((b->file == NULL)
274        || (b->file[0] == 0))
275      {
276 	b->c_time = 0;
277 	return;
278      }
279 
280    strcpy (file, b->dir);
281    strcat (file, b->file);
282 
283    if (0 == sys_file_mod_time (file))
284      b->c_time = 0;
285    else
286      b->c_time = sys_time ();
287 }
288 
set_file_modes(void)289 void set_file_modes (void) /*{{{*/
290 {
291    char *type;
292 
293    if (CBuf == NULL) return;
294 
295    jed_set_buffer_ctime (CBuf);
296 
297    if ((CBuf->file != NULL)
298        && (CBuf->file[0] != 0))
299      {
300 #if defined(__MSDOS__) && !defined(W_OK)
301 #define W_OK 2
302 #define F_OK 0
303 #endif
304 
305 #ifdef W_OK
306 #ifdef __GO32__
307 # define access i386_access
308 #endif
309 	char name [JED_MAX_PATH_LEN + 256];
310 #ifndef VMS
311 	  {
312 	     /* COmment:  I need a more generic call to contruct a directory
313 	      * name.  site.sl already does this properly.
314 	      */
315 	     int n;
316 	     strcpy (name, CBuf->dir);
317 	     n = strlen (name);
318 	     if (n >
319 #ifdef IBMPC_SYSTEM
320 		 3		       /* allow C:/file */
321 #else
322 		 1		       /* allow /file */
323 #endif
324 		 )
325 	       {
326 		  name[n - 1] = 0;     /* knock off slash */
327 		  if (!access (name, F_OK) && (access (name, W_OK)))
328 		    CBuf->flags |= READ_ONLY;
329 	       }
330 	  }
331 #endif  /* NOT VMS */
332 	sprintf (name, "%s%s", CBuf->dir, CBuf->file);
333 	if (!access(name, F_OK) && access(name, W_OK))
334 	  CBuf->flags |= READ_ONLY;
335 #endif /* W_OK */
336 	CBuf->flags |= AUTO_SAVE_BUFFER;
337 	CBuf->hits = 0;
338 	type = file_type(CBuf->file);
339      }
340    else type = NULL;
341 
342    CBuf->modes = NO_MODE;
343 #if JED_HAS_LINE_ATTRIBUTES
344    CBuf->min_unparsed_line_num = 1;
345    CBuf->max_unparsed_line_num = Max_LineNum + CBuf->nup;
346 #endif
347    if (type != NULL)
348      SLang_run_hooks("mode_hook", 1, type);
349 }
350 
351 /*}}}*/
352 
353 /*{{{ reading/inserting files */
354 
read_file(char * file)355 int read_file(char *file) /*{{{*/
356 {
357    int fp;
358    int n, status;
359 
360    if ((fp = sys_open(file, 0)) < 0)
361      {
362 	status = file_status(file);
363 	if (!status) return(-1);  /* file does not exist */
364 	return(-2); /* exists but not readable */
365      }
366    CBuf->kfcode = is_kanji_filecode(file);
367 
368    n = read_file_pointer(fp);
369    close(fp);
370    eob();
371    if ('\n' == *(CLine->data + Point)) make_line(2);
372 
373    VFile_Mode = VFILE_TEXT;
374    return n;
375 }
376 
377 /*}}}*/
insert_file_pointer(VFILE * vp)378 int insert_file_pointer(VFILE *vp) /*{{{*/
379 {
380    int n = 0;
381    unsigned int num;
382    unsigned char *vbuf, *p;
383 
384    Suspend_Screen_Update = 1;
385    while(NULL != (p = vbuf = (unsigned char *) vgets(vp, &num)))
386      {
387 	n++;
388 	if (SLang_Error) break;
389 	p = KanjiCodeConv(vbuf, &num, CBuf->kfcode, kSLcode, SKanaToDKana);
390 	quick_insert(p, (int) num);
391 	if(p != vbuf)	free(p);
392      }
393    return(n);
394 }
395 
396 /*}}}*/
insert_file(char * file)397 int insert_file(char *file) /*{{{*/
398 {
399    VFILE *vp;
400    int n;
401    int code;
402 
403    if (NULL == (vp = vopen(file, 0, VFile_Mode))) return(-1);
404    code = CBuf->kfcode;
405    CBuf->kfcode = is_kanji_filecode(file);
406    n = insert_file_pointer(vp);
407    CBuf->kfcode = code;
408    vclose(vp);
409    return(n);
410 }
411 
412 /*}}}*/
413 
414 /*}}}*/
415 
416 /*{{{ writing to files */
417 
418 #ifdef __unix__
419 # define BUFSIZE 0x10000
420 #else
421 #ifdef VMS
422 # define BUFSIZE 0x3FFF
423 #else
424 # define BUFSIZE 512
425 #endif
426 #endif
427 
428 static int Output_Buffer_Size = BUFSIZE;
429 static char Output_Buffer[BUFSIZE];
430 static char *Output_Bufferp;
431 static char *Output_Bufferp_max;
432 
433 
434 /* definitely perform the write.  Return number of chars written */
jed_write1(int fd,unsigned char * b,unsigned int n)435 static int jed_write1(int fd, unsigned char *b, unsigned int n) /*{{{*/
436 {
437 #if !defined(IBMPC_USE_ASM)
438    int len;
439    unsigned int total = 0;
440 #ifdef VMS
441    register char *bmax;
442 #endif
443 
444    while (total < n)
445      {
446 	len = n - total;
447 #ifdef VMS
448 	if (VMS_write_rfm_fixed)
449 	  {
450 	  }
451 	/* VMS wants to terminate a record with a cr so adjust for this
452 	 * unfortunate fact.  The len - 1 stuff is so *bmax does not peek
453 	 * beyond its boundary.
454 	 */
455 	bmax = b + (len - 1);
456 	while ((bmax > b) && (*bmax != '\n')) bmax--;
457 	if (bmax == b) bmax = b + (len - 1); /* cannot be helped */
458 	len = (int) (bmax - b) + 1;
459 #endif
460 	while (-1 == (len = write (fd, b, len)))
461 	  {
462 #ifdef EINTR
463 	     if (errno == EINTR)
464 	       continue;
465 #endif
466 #ifdef EAGAIN
467 	     if (errno == EAGAIN)
468 	       {
469 		  sleep (1);
470 		  continue;
471 	       }
472 #endif
473 #ifdef ENOSPC
474 	     if (errno == ENOSPC)
475 	       {
476 		  msg_error ("Write Failed: Disk Full.");
477 		  return total;
478 	       }
479 #endif
480 	     msg_error ("Write Failed: Unknown Error.");
481 	     return total;
482 	  }
483 
484 	total += (unsigned int) len;
485 	b += len;
486      }
487    return total;
488 #else
489    int num = -1;
490    asm mov ah, 40h
491    asm mov bx, fd
492    asm mov cx, n
493    asm push ds
494    asm lds dx, dword ptr b
495    asm int 21h
496    asm pop ds
497    asm jc L1
498    asm mov num, ax		       /* number of bytes written */
499    L1:
500    return(num);
501 #endif
502 }
503 
504 /*}}}*/
505 
506 
507 /* RMS wants to start a NEW record after a write so just forget it! */
508 /* maybe do write-- return number of chars possibly written */
jed_write(int fd,unsigned char * b,unsigned int n)509 static int jed_write(int fd, unsigned char *b, unsigned int n) /*{{{*/
510 {
511    int num, max, nl_flag = 0;
512    unsigned int nsave = n;
513 #if SUPPORT_CRONLY
514    int cr_flag = CBuf->flags & (ADD_CR_ON_WRITE_FLAG | CR_ONLY_ON_WRITE_FLAG);
515 #else
516    int cr_flag = CBuf->flags & ADD_CR_ON_WRITE_FLAG;
517 #endif
518    unsigned char *wknj, *wknj_base, *b_save;
519 
520    b_save = b;
521    wknj_base = b = KanjiCodeConv(b, &n, kSLcode, CBuf->kfcode, FALSE);
522 #ifdef MAP_CR_TO_NL_FLAG
523    if (CBuf->flags & MAP_CR_TO_NL_FLAG)
524      {
525 	unsigned char *bmax = b + n;
526 	char *p, *pmax, ch;
527 	p = Output_Bufferp;
528 	pmax = Output_Bufferp_max;
529 
530 	while (b < bmax)
531 	  {
532 	     ch = *b++;
533 	     if ((ch == '\r') || (ch == '\n'))
534 	       {
535 #if SUPPORT_CRONLY
536 		  if (cr_flag & ADD_CR_ON_WRITE_FLAG)
537 #else
538 		  if (cr_flag)
539 #endif
540 		    {
541 		       *p++ = ch;
542 		       if (p == pmax)
543 			 {
544 			    num = (int) (Output_Bufferp_max - Output_Bufferp);
545 			    if (num != jed_write1 (fd, Output_Bufferp, num))
546 			      return -1;
547 			    Output_Bufferp = Output_Buffer;
548 			    p = Output_Bufferp;
549 			 }
550 		    }
551 #if SUPPORT_CRONLY
552 		  if (cr_flag & CR_ONLY_ON_WRITE_FLAG)
553 		    *p++ = '\r';
554 		  else
555 #endif
556 		    *p++ = '\n';
557 	       }
558 	     else *p++ = ch;
559 
560 	     if (p == pmax)
561 	       {
562 		  num = (int) (Output_Bufferp_max - Output_Bufferp);
563 		  if (num != jed_write1 (fd, Output_Buffer, num))
564 		    return -1;
565 		  Output_Bufferp = Output_Buffer;
566 		  p = Output_Bufferp;
567 	       }
568 	  }
569 	Output_Bufferp = p;
570 	if(b_save != wknj_base)	SLfree(wknj_base);
571 	return nsave;
572      }
573 #endif
574    /* amount of space left in buffer */
575    /* copy whats in b to the output buffer */
576    while (n > 0)
577      {
578 	num = (int) (Output_Bufferp_max - Output_Bufferp);
579 	if ((int) n > num)
580 	  {
581 #ifdef VMS
582 	     max = (int) (Output_Bufferp - Output_Buffer);
583 	     if (max)
584 	       {
585 		  if (max != jed_write1(fd, Output_Buffer, max))
586 		    return(-1);
587 		  Output_Bufferp = Output_Buffer;
588 		  continue;
589 	       }
590 #endif
591 	     max = num;
592 	     SLMEMCPY(Output_Bufferp, b, max);
593 	     Output_Bufferp += max;
594 	  }
595 
596 	else if (cr_flag &&
597 		 (*(b + (n - 1)) == '\n') && (VFile_Mode == VFILE_TEXT))
598 	  {
599 	     max = n - 1;
600 	     SLMEMCPY(Output_Bufferp, b, max);
601 	     Output_Bufferp += max;
602 	     *Output_Bufferp++ = '\r';
603 	     max++;
604 
605 #if SUPPORT_CRONLY
606 	     if (!(cr_flag & CR_ONLY_ON_WRITE_FLAG))
607 #endif
608 	       {
609 		  /* can only write the \r */
610 		  if (n == (unsigned int) num) nl_flag = 1; else *Output_Bufferp++ = '\n';
611 	       }
612 	  }
613 	else
614 	  {
615 	     max = n;
616 	     SLMEMCPY(Output_Bufferp, b, max);
617 	     Output_Bufferp += max;
618 	  }
619 
620 	if (Output_Bufferp == Output_Bufferp_max)
621 	  {
622 	     Output_Bufferp = Output_Buffer;
623 	     if (Output_Buffer_Size != jed_write1(fd, Output_Buffer, Output_Buffer_Size)) return(-1);
624 	     if (nl_flag)
625 	       {
626 		  nl_flag = 0;
627 		  *Output_Bufferp++ = '\n';
628 	       }
629 	  }
630 	b += max;
631 	n -= max;
632      }
633    if(b_save != wknj_base)	SLfree(wknj_base);
634    return(nsave);
635 }
636 
637 /*}}}*/
638 
639 /* returns -1 on failure */
write_region_to_fp(int fp)640 int write_region_to_fp(int fp) /*{{{*/
641 {
642    register int pnt, len;
643    register Line *first, *last;
644    int last_pnt, n = 0;
645    char *err = "Write Failed!";
646 
647 #ifndef VMS
648    char nl = '\n';
649 #endif
650 
651    Output_Bufferp = Output_Buffer;
652    Output_Bufferp_max = Output_Buffer + BUFSIZE;
653    Output_Buffer_Size = BUFSIZE;
654 
655 #ifdef VMS
656    if (VMS_write_rfm_fixed && (vms_max_rec_size <= BUFSIZE))
657      {
658 	Output_Buffer_Size = vms_max_rec_size;
659      }
660    else VMS_write_rfm_fixed = 0;
661 #endif
662 
663    if (!check_region(&Number_One)) return(-1);
664    last = CLine; last_pnt = Point;
665 
666    pop_mark(&Number_One);
667    first = CLine; pnt = Point;
668 
669    /* first should never be null without hitting last first.  If this
670       ever happens, check_region failed. */
671    while (first != last)
672      {
673 	len = first->len - pnt;
674 	if (len != jed_write(fp, (first->data + pnt), len))
675 	  {
676 	     msg_error(err);
677 	  }
678 
679 	/* This goes here inside the loop because it is possible for external
680 	   events to set error_buffer */
681 	pnt = 0;
682 	if (SLang_Error) break;
683 	first = first->next;
684 	n++;
685      }
686 
687    if (!SLang_Error && (last_pnt != 0))
688      {
689 	len = last_pnt - pnt;
690 	if (len != jed_write(fp, (last->data + pnt), len))
691 	  {
692 	     msg_error(err);
693 	  }
694 	n++;
695      }
696 #ifndef VMS
697    if ((Require_Final_Newline) && (CBuf->end == last))
698      {
699 	eob(); if (Point) jed_write(fp, &nl, 1);
700      }
701 #endif
702 
703 
704    /* Now flush output buffer if necessary */
705 
706    len = (int) (Output_Bufferp - Output_Buffer);
707    if (!SLang_Error && len) if (len != jed_write1(fp, (unsigned char *)Output_Buffer, len))
708      {
709 	msg_error(err);
710      }
711 
712    Output_Bufferp = Output_Buffer;
713 
714 
715    pop_spot();
716    VFile_Mode = VFILE_TEXT;
717    if (SLang_Error) return(-1);
718    return(n);
719 }
720 
721 /*}}}*/
722 
jed_close(int fp)723 static int jed_close (int fp) /*{{{*/
724 {
725    while (-1 == close(fp))
726      {
727 #ifdef EINTR
728 #ifndef IBMPC_SYSTEM
729 	if (errno == EINTR)
730 	  {
731 	     errno = 0;
732 	     sleep (1);
733 	     continue;
734 	  }
735 #endif
736 #endif
737 	msg_error ("Error closing file.  File system may be full.");
738 	return -1;
739      }
740    return 0;
741 }
742 
743 /*}}}*/
744 
write_region(char * file)745 int write_region (char *file) /*{{{*/
746 {
747    int fp;
748    int n;
749 
750    if (!check_region(&Number_Zero)) return(-1);
751    if ((fp = sys_open(file, 1)) < 0)
752      {
753 	jed_verror ("Unable to open %s for writing.", file);
754 	return -1;
755      }
756    n = write_region_to_fp(fp);
757    if (-1 == jed_close (fp)) n = -1;
758 
759    return(n);
760 }
761 
762 /*}}}*/
763 
764 
765 /* returns -1 on failure and number of lines on success */
write_file(char * file)766 static int write_file(char *file) /*{{{*/
767 {
768    Mark *m;
769    int n = -1;
770    int fnl;
771 
772 #ifdef VMS
773    register Line *l;
774    register int len = 0, max = 0;
775 #endif
776 
777    push_spot();
778 
779 #if JED_HAS_SAVE_NARROW
780    jed_push_narrow ();
781    jed_widen_whole_buffer (CBuf);
782 #endif
783 
784 #ifdef VMS
785    l = CBuf->beg;
786    while (l != NULL)
787      {
788 	len = l->len;
789 	if (len > max) max = len;
790 	l = l->next;
791      }
792    vms_max_rec_size = max;
793 #endif
794 
795    bob();
796    push_mark();  m = CBuf->marks;
797    eob();
798    fnl = Require_Final_Newline;
799    if (CBuf->flags & BINARY_FILE)
800      {
801 	VFile_Mode = VFILE_BINARY;
802 	Require_Final_Newline = 0;
803 
804 #ifdef VMS
805 	vms_max_rec_size = 512;
806 #endif
807      }
808 
809    n = write_region(file);
810 
811    Require_Final_Newline = fnl;
812    VFile_Mode = VFILE_TEXT;
813    if (m == CBuf->marks) pop_mark(&Number_Zero);
814 
815 #if JED_HAS_SAVE_NARROW
816    jed_pop_narrow ();
817 #endif
818 
819    pop_spot();
820    return(n);
821 }
822 
823 /*}}}*/
824 
append_to_file(char * file)825 int append_to_file(char *file) /*{{{*/
826 {
827    int fp;
828    int n;
829 
830    if ((fp = sys_open(file, 2)) < 0) return(-1);
831    n = write_region_to_fp(fp);
832    if (-1 == jed_close (fp)) n = -1;
833    check_buffers();
834    return(n);
835 }
836 
837 /*}}}*/
838 
839 /*}}}*/
840 
make_autosave_filename(char * save,char * dir,char * file)841 static int make_autosave_filename(char *save, char *dir, char *file) /*{{{*/
842 {
843    char *s;
844 
845    if (*file == 0) return(0);
846 
847 
848    if (1 == SLang_run_hooks ("make_autosave_filename", 2, dir, file))
849      {
850 	if (SLang_pop_slstring(&s)) return(0);
851 	strncpy(save, s, JED_MAX_PATH_LEN - 2);
852 	save[JED_MAX_PATH_LEN - 1] = 0;
853 	SLang_free_slstring (s);
854      }
855    else
856      {
857 #if defined(IBMPC_SYSTEM)
858 	sprintf(save, "%s#%s", dir, file);
859 #else
860 # ifdef VMS
861 	sprintf(save, "%s_$%s;1", dir, file);
862 # else
863 	sprintf(save, "%s#%s#", dir, file);
864 # endif
865 #endif
866      }
867    return 1;
868 }
869 
870 /*}}}*/
871 
872 #ifndef VMS
jed_copy_file(char * from,char * to)873 int jed_copy_file (char *from, char *to) /*{{{*/
874 {
875    int mode;
876    short uid, gid;
877    FILE *fp0, *fp1;
878    char buf[0x7FFF];
879    unsigned int readlen;
880    int ret;
881    struct stat st;
882 #ifdef HAVE_UTIME
883    struct utimbuf ut;
884 #endif
885 
886    if (1 != sys_chmod (from, 0, &mode, &uid, &gid))
887      return -1;		       /* from does not exist as regular file */
888 
889    /* Need file modification times so that they can be preserved. */
890    if (-1 == stat (from, &st))
891      return -1;
892 
893    fp0 = fopen (from, "rb");
894    if (fp0 == NULL) return -1;
895 
896    fp1 = fopen (to, "wb");
897    if (fp1 == NULL)
898      {
899 	(void) fclose (fp0);
900 	return -1;
901      }
902 
903    (void) chmod (to, 0600);
904 
905    ret = 0;
906    do
907      {
908 	readlen = fread (buf, 1, sizeof(buf), fp0);
909 	if (readlen)
910 	  {
911 	     if (readlen != fwrite (buf, 1, readlen, fp1))
912 	       {
913 		  ret = -1;
914 		  break;
915 	       }
916 	  }
917      }
918    while (readlen == sizeof (buf));
919 
920    fclose (fp0);
921 
922    if (EOF == fclose (fp1))
923      {
924 	ret = -1;
925      }
926 
927    (void) sys_chmod (to, 1, &mode, &uid, &gid);
928 
929 #ifdef HAVE_UTIME
930    /* Set file modification times */
931    ut.actime = st.st_atime;
932    ut.modtime = st.st_mtime;
933    (void) utime (to, &ut);
934 #endif
935 
936    return ret;
937 }
938 /*}}}*/
939 #endif				       /* NOT VMS */
940 
941 #ifndef VMS
perform_backup(char * from,char * to,int try_force_rename)942 static int perform_backup (char *from, char *to, int try_force_rename) /*{{{*/
943 {
944    int ret = -1;
945    int use_copy = Jed_Backup_By_Copying;
946 #ifdef REAL_UNIX_SYSTEM
947    /* If the file has hardlinks, then backup by copying. */
948    struct stat st;
949 
950    if (0 == stat (from, &st))
951      {
952 	if (st.st_nlink > 1)
953 	  use_copy = 1;
954      }
955 #endif
956 
957    if (try_force_rename
958        || (use_copy == 0))
959      {
960 	(void) unlink(to);
961 #ifdef __WIN32__
962 	/* Rename is broken on win32 */
963 	ret = jed_win32_rename (from, to);
964 #else
965 	ret = rename (from, to);
966 #endif
967      }
968 
969    if (ret == -1)
970      ret = jed_copy_file (from, to);
971 
972    return ret;
973 }
974 /*}}}*/
975 #endif
976 
sys_file_mod_time(char * file)977 unsigned long sys_file_mod_time(char *file) /*{{{*/
978 {
979    struct stat buf;
980 
981    if (stat(file, &buf) < 0) return 0;
982 
983    return (unsigned long) buf.st_mtime;
984 }
985 
986 /*}}}*/
987 
write_file_with_backup(char * dir,char * file)988 int write_file_with_backup(char *dir, char *file) /*{{{*/
989 {
990    char neew[JED_MAX_PATH_LEN]; char autosave_file[JED_MAX_PATH_LEN];
991    int n;
992    int mode, do_mode;
993    short uid, gid;
994    char *mode_string;
995 #ifndef VMS
996    char *old = NULL;
997    int backup_went_ok;
998 #endif
999 #ifdef __os2__
1000    PHOLDFEA EAs;
1001 #endif
1002 
1003    if (*file == 0) return(-1);
1004 
1005    sprintf(neew, "%s%s", dir, file);
1006 
1007    *autosave_file = 0;
1008    if (CBuf->flags & AUTO_SAVE_BUFFER)
1009       (void) make_autosave_filename(autosave_file, dir, file);
1010 
1011    do_mode = sys_chmod(neew, 0, &mode, &uid, &gid);
1012    if ((do_mode != 0) && (do_mode != 1)) return -1;
1013    /* IF do_mode == 0, then the file does not exist.  This means that
1014     * there is nothing to backup.  If do_mode == 1, the file is a regular
1015     * file which we do want to backup.
1016     */
1017    if (NULL == (mode_string = CBuf->mode_string))
1018      mode_string = "";
1019    if (-1 == SLang_run_hooks ("save_buffer_hook", 2, neew, mode_string))
1020      {
1021 	auto_save_buffer (CBuf);
1022 	return -1;
1023      }
1024 
1025 #ifndef VMS
1026 
1027 # ifdef __os2__
1028    EAs = QueryEAs (neew);
1029 # endif
1030 
1031    backup_went_ok = 0;
1032    if (do_mode
1033        && ((CBuf->flags & NO_BACKUP_FLAG) == 0)
1034        && (1 == SLang_run_hooks("make_backup_filename", 2, dir, file)))
1035      {
1036 	if ((0 == SLang_pop_slstring(&old))
1037 	    && (*old != 0))
1038 	  {
1039 	     backup_went_ok = (0 == perform_backup (neew, old, 0));
1040 	  }
1041      }
1042 #endif				       /* NOT VMS */
1043 
1044    if (-1 != (n = write_file(neew)))
1045      {
1046 	if (*autosave_file)
1047 	  {
1048 	     sys_delete_file(autosave_file);
1049 	  }
1050 
1051 	if (do_mode) /* must be an existing file, so preserve mode */
1052 	  {
1053 #if defined(__MSDOS__)
1054 	     /* Want the archive bit set since this is a new version */
1055 	     mode |= 1 << 5;
1056 #endif
1057 	     sys_chmod (neew, 1, &mode, &uid, &gid);
1058 #ifdef __os2__
1059 	     WriteEAs (neew, EAs);
1060 #endif
1061 	  }
1062 	/* This is for NFS time problems */
1063 	CBuf->c_time = sys_file_mod_time(neew);
1064 
1065 	/* Since we wrote the buffer to the file, it is not modified. */
1066 	if (
1067 #if JED_FILE_PRESERVE_CASE
1068 	    (0 == strcmp(file, CBuf->file)) && (0 == strcmp(dir, CBuf->dir))
1069 #else
1070 	    (0 == jed_case_strcmp (file, CBuf->file))
1071 	     && (0 == jed_case_strcmp (dir, CBuf->dir))
1072 #endif
1073 	    )
1074 	  CBuf->flags &= ~FILE_MODIFIED;
1075 
1076 	/* CBuf->c_time = sys_time(); */
1077      }
1078 #ifndef VMS
1079    /* error -- put it back */
1080    else if (backup_went_ok) perform_backup (old, neew, 1);
1081 
1082    if (old != NULL) SLang_free_slstring (old);
1083 #endif
1084    return(n);
1085 }
1086 
1087 /*}}}*/
1088 
auto_save_buffer(Buffer * b)1089 void auto_save_buffer(Buffer *b) /*{{{*/
1090 {
1091    char tmp[JED_MAX_PATH_LEN];
1092    Buffer *old_buf;
1093    int old_filecode;
1094    unsigned int vfm = VFile_Mode;
1095 
1096    if (b == NULL) return;
1097    b->hits = 0;
1098    if ((0 == (b->flags & BUFFER_MODIFIED))
1099        || (0 == (b->flags & (AUTO_SAVE_BUFFER | AUTO_SAVE_JUST_SAVE))))
1100      return;
1101 
1102 #if !JED_HAS_SAVE_NARROW
1103    if (b->narrow != NULL) return;
1104 #endif
1105 
1106    old_buf = CBuf;
1107    switch_to_buffer(b);
1108    old_filecode = b->kfcode;
1109    b->kfcode = kSLcode;
1110 
1111    if (b->flags & BINARY_FILE)  VFile_Mode = VFILE_BINARY;
1112    else VFile_Mode = VFILE_TEXT;
1113 
1114    if (b->flags & AUTO_SAVE_BUFFER)
1115      {
1116 	if (make_autosave_filename(tmp, b->dir, b->file))
1117 	  {
1118 	     flush_message("autosaving...");
1119 	     sys_delete_file(tmp);
1120 	     write_file(tmp);
1121 #ifndef IBMPC_SYSTEM
1122 	     (void) chmod (tmp, 0600);
1123 #endif
1124 	     message("autosaving...done");
1125 	  }
1126       }
1127    else if (write_file_with_backup(b->dir, b->file) >= 0)
1128      {
1129 	b->flags &= ~BUFFER_MODIFIED;
1130      }
1131 
1132    b->kfcode = old_filecode;
1133    switch_to_buffer(old_buf);
1134    VFile_Mode = vfm;
1135 }
1136 
1137 /*}}}*/
1138 
auto_save_all(void)1139 void auto_save_all (void) /*{{{*/
1140 {
1141     Buffer *b;
1142 
1143    if (NULL == (b = CBuf)) return;
1144    do
1145      {
1146 	jed_widen_whole_buffer (b);
1147 	if (CBuf == NULL) return;
1148 	if (*b->file != 0) auto_save_buffer(b);
1149 	if (CBuf == NULL) return;
1150 
1151 	b = b->next;
1152      }
1153    while (b != CBuf);
1154 }
1155 
1156 /*}}}*/
1157 
1158 #ifdef REAL_UNIX_SYSTEM
1159 /*{{{ symbolic link stuff */
1160 
is_link(char * f,char * f1)1161 static int is_link(char *f, char *f1) /*{{{*/
1162 {
1163    struct stat s;
1164    unsigned int l;
1165    int is_dir = 0;
1166    char work[JED_MAX_PATH_LEN];
1167 
1168    l = strlen(f);
1169    if (l == 0) return 0;
1170    l--;
1171    if ((l > 1) && (f[l] == '/'))
1172      {
1173 	strcpy(work, f);
1174 	is_dir = 1;
1175 	f = work;
1176 	f[l] = 0;
1177      }
1178 
1179 
1180    if (( lstat(f, &s) == -1 )
1181        /* || ((s.st_mode & S_IFMT)  S_IFLNK)) */
1182        || (((s.st_mode & S_IFMT) & S_IFLNK) == 0))
1183      return(0);
1184 
1185    l = JED_MAX_PATH_LEN - 1;
1186    if (is_dir)
1187      {
1188 	/* This way, it will be expanded properly upon return */
1189 	*f1++ = '.'; *f1++ = '.'; *f1++ = '/';
1190 	l -= 4;			       /* 1 for final slash */
1191      }
1192 
1193    if (-1 == (int) (l = readlink(f, f1, l))) return 0;
1194    if (is_dir) f1[l++] = '/';
1195    f1[l] = 0;
1196 
1197    /* If the link is an absolute pathname (starts with /) then the
1198     * ../ prefix should not go there.
1199     */
1200    if (is_dir && (*f1 == '/'))
1201      {
1202 	char ch;
1203 
1204 	f = f1 - 3;
1205 	while (0 != (ch = *f1++))
1206 	  *f++ = ch;
1207 
1208 	*f = 0;
1209      }
1210 
1211    return(1);
1212 }
1213 
1214 /*}}}*/
1215 
1216 /* This routine should be modified to work with all components of the path
1217  * and not just the last component.  For example, suppose /usr/lib/jed is a
1218  * link to /usr/local/src/jed and one tries to read the file
1219  * /usr/lib/jed/lib/site.sl.  This should be expanded to
1220  * /usr/local/lib/jed/lib/site.sl.  Currently, it will only have an effect if
1221  * site.sl is itself a link.
1222  */
expand_link(char * f)1223 char *expand_link(char *f) /*{{{*/
1224 {
1225    char work[JED_MAX_PATH_LEN], lnk[JED_MAX_PATH_LEN];
1226    char *d = expand_filename(f);
1227 
1228 
1229    while (is_link(d, lnk))
1230      {
1231 	char *w, *w1, ch;
1232 
1233 	if (*lnk == '/')	       /* absolute */
1234 	  strcpy (work, lnk);
1235 	else
1236 	  {
1237 	     strcpy (work, d);
1238 	     *(extract_file(work)) = 0;
1239 	     strcat (work, lnk);
1240 	  }
1241 
1242 	/* Collapse multiple // since expand_filename will interpret them
1243 	 * differently.
1244 	 */
1245 	w = w1 = work;
1246 	while ((ch = *w1++) != 0)
1247 	  {
1248 	     *w++ = ch;
1249 	     if (ch == '/') while (*w1 == '/') w1++;
1250 	  }
1251 	*w = 0;
1252 
1253 	d = expand_filename(work);
1254      }
1255 
1256    return (d);
1257 }
1258 
1259 /*}}}*/
1260 
1261 /*}}}*/
1262 #endif
1263 
visit_file(char * dir,char * file)1264 void visit_file(char *dir, char *file) /*{{{*/
1265 {
1266    if (
1267 #if JED_FILE_PRESERVE_CASE
1268        strcmp(file, CBuf->file) || strcmp(dir, CBuf->dir)
1269 #else
1270        jed_case_strcmp (file, CBuf->file) || jed_case_strcmp (dir, CBuf->dir)
1271 #endif
1272        )
1273      {
1274 	buffer_filename (CBuf, dir, file);
1275      }
1276    /* We have already taken care of this in write buffer function.
1277     */
1278    /* CBuf->c_time = sys_time(); */
1279 
1280    check_buffers();
1281 }
1282 
1283 /*}}}*/
1284 
dir_file_merge(char * dir,char * file)1285 char *dir_file_merge(char *dir, char *file) /*{{{*/
1286 /*
1287  * returns result of merging dir with file. If file is empty, dir is
1288  * considered to be whole file.
1289  */
1290 {
1291    char name[2 * JED_MAX_PATH_LEN];
1292 
1293    strcpy (name, dir);
1294    if ((file != NULL) && *file)
1295      {
1296 	fixup_dir(name);
1297 	strcat(name, file);
1298      }
1299 
1300    return expand_filename(name);
1301 }
1302 
1303 /*}}}*/
1304 
file_status(char * file)1305 int file_status(char *file) /*{{{*/
1306 /*
1307  *  Returns a coded integer about file.  If the file does not exist, 0 is
1308  *  returned.  Meaning:
1309  *
1310  *     2 file is a directory
1311  *     1 file exists
1312  *     0 file does not exist.
1313  *    -1 no access.
1314  *    -2 path invalid
1315  *    -3 unknown error
1316  */
1317 {
1318    int mode = 0;
1319    short uid, gid;
1320    return sys_chmod(file, 0, &mode, &uid, &gid);
1321 }
1322 
1323 /*}}}*/
file_changed_on_disk(Buffer * buf,char * file)1324 int file_changed_on_disk (Buffer *buf, char *file) /*{{{*/
1325 {
1326    unsigned long t;
1327 
1328    t = sys_file_mod_time(file);
1329    if (t == 0)
1330      {
1331 	/* File does not exist.  If the buffer has not been modified since
1332 	 * the last save, then the file has changed on the disk.
1333 	 */
1334 #if 1
1335 	return 0;
1336 #else
1337 	if (buf->c_time == 0)
1338 	  return 0;
1339 
1340 	return (0 == (buf->flags & BUFFER_MODIFIED));
1341 #endif
1342      }
1343 
1344    if (t > buf->c_time)
1345      {
1346 	if (buf->c_time == 0)	       /* new buffer, writing to exiting file */
1347 	  return 0;
1348 
1349 	return 1;
1350      }
1351 
1352    /* FIXME: The file may still have been changed via a rename operation.  Check
1353     * the inodes.
1354     */
1355 
1356    return 0;
1357 }
1358 
1359 /*}}}*/
file_time_cmp(char * file1,char * file2)1360 int file_time_cmp(char *file1, char *file2) /*{{{*/
1361 {
1362    unsigned long t1, t2;
1363 
1364    t1 = sys_file_mod_time(file1);
1365    t2 = sys_file_mod_time(file2);
1366     /*These times are modification  times from 1970.  Hence, the bigger
1367      * number represents the more recent change.  Let '>' denote
1368      * 'more recent than'.  This function returns:
1369      *	   1:  file1 > file2
1370      *	   0:  file 1 == file2
1371      *	   -1: otherwise.
1372      *	So:
1373      */
1374    if (t1 == t2) return(0);
1375    if (t1 > t2) return(1);
1376    return(-1);
1377 }
1378 
1379 /*}}}*/
1380 
auto_save(void)1381 void auto_save(void) /*{{{*/
1382 {
1383    auto_save_buffer(CBuf);
1384 }
1385 
1386 /*}}}*/
1387 
check_buffer(Buffer * b)1388 void check_buffer(Buffer *b) /*{{{*/
1389 {
1390 #ifdef REAL_UNIX_SYSTEM
1391    /* Update (or even invalidate) inode information since directories may have
1392     * been renamed, etc...
1393     */
1394    (void) get_inode_info (b->dir, &b->device, &b->inode);
1395 #endif
1396 
1397    if ((*b->file != 0)
1398        && file_changed_on_disk(b, dir_file_merge(b->dir, b->file)))
1399      {
1400 	b->flags |= FILE_MODIFIED;
1401      }
1402    else b->flags &= ~FILE_MODIFIED;
1403 }
1404 
1405 /*}}}*/
check_buffers()1406 void check_buffers() /*{{{*/
1407 {
1408    Buffer *b = CBuf;
1409    do
1410      {
1411 	check_buffer(b);
1412 	b = b->next;
1413      }
1414    while (b != CBuf);
1415 }
1416 
1417 /*}}}*/
1418 
set_file_trans(int * mode)1419 void set_file_trans(int *mode) /*{{{*/
1420 {
1421    if (*mode) VFile_Mode = VFILE_BINARY; else VFile_Mode = VFILE_TEXT;
1422 }
1423 
1424 /*}}}*/
1425 
read_file_pointer(int fp)1426 int read_file_pointer(int fp) /*{{{*/
1427 {
1428    int n = 1;
1429    unsigned int num;
1430    unsigned char *vbuf, *p;
1431    VFILE *vp;
1432 
1433    if (SLang_Error || (vp = vstream(fp, MAX_LINE_LEN, VFile_Mode)) == NULL) return(-1);
1434 
1435    if (NULL == (vbuf = (unsigned char *) vgets(vp, &num))) return(0);
1436    p = KanjiCodeConv(vbuf, &num, CBuf->kfcode, kSLcode, SKanaToDKana);
1437 
1438 #ifdef KEEP_SPACE_INFO
1439    if (CLine->space < num)
1440 #endif
1441      remake_line(CLine->len + num + 1);
1442 
1443    SLMEMCPY((char *) CLine->data, (char *) p, (int) num);
1444    if(p != vbuf)	SLfree(p);
1445    CLine->len = num;
1446 
1447    while(NULL != (vbuf = (unsigned char *) vgets(vp, &num)))
1448      {
1449 	n++;
1450 	p = KanjiCodeConv(vbuf, &num, CBuf->kfcode, kSLcode, SKanaToDKana);
1451 	if ((num == 1) && (*vbuf == '\n')) make_line(num); else make_line(num + 1);
1452 	SLMEMCPY((char *) CLine->data, (char *) p, (int) num);
1453 	if(p != vbuf)	SLfree(p);
1454 	CLine->len = num;
1455 	if (SLang_Error) break;
1456      }
1457    if (vp->buf != NULL) SLfree(vp->buf);
1458 
1459 #if SUPPORT_CRONLY
1460    if (vp->cr_flag)
1461      {
1462 	if (vp->cr_flag & CR_ONLY_ON_WRITE_FLAG) CBuf->flags |= CR_ONLY_ON_WRITE_FLAG;
1463 	else CBuf->flags |= ADD_CR_ON_WRITE_FLAG;
1464      }
1465    else CBuf->flags &= ~(ADD_CR_ON_WRITE_FLAG | CR_ONLY_ON_WRITE_FLAG);
1466 #else
1467    if (vp->cr_flag) CBuf->flags |= ADD_CR_ON_WRITE_FLAG;
1468    else CBuf->flags &= ~ADD_CR_ON_WRITE_FLAG;
1469 #endif
1470 
1471    SLfree ((char *)vp);
1472    return n;
1473 }
1474 
1475 /*}}}*/
1476 
1477 #ifdef REAL_UNIX_SYSTEM
get_inode_info(char * dir,int * device,int * inode)1478 int get_inode_info (char *dir, int *device, int *inode) /*{{{*/
1479 {
1480    struct stat st;
1481    char work [JED_MAX_PATH_LEN + 512];
1482    char *f;
1483 
1484    f = extract_file (dir);
1485    if (*f != 0)
1486      {
1487 	unsigned int len = f - dir;
1488 	strncpy (work, dir, len);
1489 	work[len] = 0;
1490 	dir = work;
1491      }
1492 
1493    *inode = *device = -1;
1494    if (-1 == stat (dir, &st)) return -1;
1495 
1496    *inode = st.st_ino;
1497    *device = st.st_dev;
1498 
1499    return 0;
1500 }
1501 /*}}}*/
1502 
1503 #endif
1504 
jed_set_umask(int mask)1505 void jed_set_umask (int mask)
1506 {
1507 #ifdef REAL_UNIX_SYSTEM
1508    static int default_umask;
1509 #endif
1510 
1511    if (mask == 0)
1512      {
1513 #ifdef REAL_UNIX_SYSTEM
1514 	if (default_umask != 0)
1515 	  (void) umask (default_umask);
1516 #endif
1517      }
1518    else
1519      {
1520 #ifdef REAL_UNIX_SYSTEM
1521 	int u;
1522 
1523 	u = umask (mask & 0777);
1524 	if (default_umask == 0) default_umask = u;
1525 #endif
1526      }
1527 }
1528 
1529