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