|
|
1.1 root 1: /***************************************************************************
2: * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE *
3: * is provided to you without charge, and with no warranty. You may give *
4: * away copies of JOVE, including sources, provided that this notice is *
5: * included in all the files. *
6: ***************************************************************************/
7:
8: #include "jove.h"
9: #include "io.h"
10: #include "termcap.h"
11:
12: #ifdef IPROCS
13: # include <signal.h>
14: #endif
15:
16: #ifdef MAC
17: # include "mac.h"
18: #else
19: # include <sys/stat.h>
20: #endif
21:
22: #ifdef UNIX
23: #include <sys/file.h>
24: #ifdef YP_PASSWD
25: #include <rpcsvc/ypclnt.h>
26: #endif
27: #endif
28:
29: #ifdef MSDOS
30: #include <fcntl.h>
31: #include <io.h>
32: #ifdef CHDIR
33: #include <direct.h>
34: #include <dos.h>
35: #endif
36: #endif /* MSDOS */
37: #include <errno.h>
38:
39: #ifdef MAC
40: # undef private
41: # define private
42: #endif
43:
44: #ifdef LINT_ARGS
45: private struct block
46: * b_unlink(struct block *),
47: * lookup(short);
48:
49: private char
50: * dbackup(char *, char *, char),
51: #if defined(MSDOS) && defined(CHDIR)
52: * fixpath(char *),
53: #endif
54: * getblock(disk_line, int);
55:
56: private void
57: #if defined(MSDOS) && defined(CHDIR)
58: abspath(char *, char *),
59: #endif
60: fake_blkio(struct block *, int (*)()),
61: LRUunlink(struct block *),
62: real_blkio(struct block *, int (*)());
63:
64: private int
65: #if defined(MSDOS) && defined(CHDIR)
66: Dchdir(char *),
67: #endif
68: dfollow(char *, char *);
69:
70: #else
71: private struct block
72: * b_unlink(),
73: * lookup();
74:
75: private char
76: * dbackup(),
77: #if defined(MSDOS) && defined(CHDIR)
78: * fixpath(),
79: #endif
80: * getblock();
81:
82: private void
83: #if defined(MSDOS) && defined(CHDIR)
84: abspath(),
85: #endif
86: fake_blkio(),
87: LRUunlink(),
88: real_blkio();
89:
90: private int
91: #if defined(MSDOS) && defined(CHDIR)
92: Dchdir(),
93: #endif
94: dfollow();
95: #endif /* LINT_ARGS */
96:
97: #ifdef MAC
98: # undef private
99: # define private static
100: #endif
101:
102:
103: #ifndef W_OK
104: # define W_OK 2
105: # define F_OK 0
106: #endif
107:
108: long io_chars; /* number of chars in this open_file */
109: int io_lines; /* number of lines in this open_file */
110:
111: #if defined(VMUNIX)||defined(MSDOS)
112: char iobuff[LBSIZE],
113: genbuf[LBSIZE],
114: linebuf[LBSIZE];
115: #else
116: char *iobuff,
117: *genbuf,
118: *linebuf;
119: #endif
120:
121: #ifdef BACKUPFILES
122: int BkupOnWrite = 0;
123: #endif
124:
125: void
126: close_file(fp)
127: File *fp;
128: {
129: if (fp) {
130: if (fp->f_flags & F_TELLALL)
131: add_mess(" %d lines, %D characters.",
132: io_lines,
133: io_chars);
134: f_close(fp);
135: }
136: }
137:
138: /* Write the region from line1/char1 to line2/char2 to FP. This
139: never CLOSES the file since we don't know if we want to. */
140:
141: int EndWNewline = 1;
142:
143: void
144: putreg(fp, line1, char1, line2, char2, makesure)
145: register File *fp;
146: Line *line1,
147: *line2;
148: {
149: register int c;
150: register char *lp;
151:
152: if (makesure)
153: (void) fixorder(&line1, &char1, &line2, &char2);
154: while (line1 != line2->l_next) {
155: lp = lcontents(line1) + char1;
156: if (line1 == line2) {
157: fputnchar(lp, (char2 - char1), fp);
158: io_chars += (char2 - char1);
159: } else while (c = *lp++) {
160: putc(c, fp);
161: io_chars += 1;
162: }
163: if (line1 != line2) {
164: io_lines += 1;
165: io_chars += 1;
166: #ifdef MSDOS
167: putc('\r', fp);
168: #endif /* MSDOS */
169: putc('\n', fp);
170: }
171: line1 = line1->l_next;
172: char1 = 0;
173: }
174: flush(fp);
175: }
176:
177: void
178: read_file(file, is_insert)
179: char *file;
180: {
181: Bufpos save;
182: File *fp;
183: if (!is_insert) {
184: curbuf->b_ntbf = 0;
185: set_ino(curbuf);
186: }
187: fp = open_file(file, iobuff, F_READ, !COMPLAIN, !QUIET);
188: if (fp == NIL) {
189: if (!is_insert && errno == ENOENT)
190: s_mess("(new file)");
191: else
192: s_mess(IOerr("open", file));
193: return;
194: }
195: DOTsave(&save);
196: dofread(fp);
197: if (is_insert && io_chars > 0) {
198: modify();
199: set_mark();
200: }
201: SetDot(&save);
202: getDOT();
203: close_file(fp);
204: }
205:
206: void
207: dofread(fp)
208: register File *fp;
209: {
210: char end[LBSIZE];
211: int xeof = 0;
212: Line *savel = curline;
213: int savec = curchar;
214: extern disk_line f_getputl();
215:
216: strcpy(end, linebuf + curchar);
217: xeof = f_gets(fp, linebuf + curchar, LBSIZE - curchar);
218: SavLine(curline, linebuf);
219: if (!xeof) do {
220: curline = listput(curbuf, curline);
221: xeof = f_getputl(curline, fp);
222: } while (!xeof);
223: getDOT();
224: linecopy(linebuf, (curchar = strlen(linebuf)), end);
225: SavLine(curline, linebuf);
226: IFixMarks(savel, savec, curline, curchar);
227: }
228:
229: void
230: SaveFile()
231: {
232: if (IsModified(curbuf)) {
233: if (curbuf->b_fname == 0)
234: WriteFile();
235: else {
236: filemunge(curbuf->b_fname);
237: #ifndef MAC
238: #ifndef MSDOS /* not sure - kg - */
239: chk_mtime(curbuf, curbuf->b_fname, "save");
240: #endif /* MSDOS */
241: #endif /* MAC */
242: file_write(curbuf->b_fname, 0);
243: unmodify();
244: }
245: } else
246: message("No changes need to be written.");
247: }
248:
249: char *HomeDir; /* home directory */
250: int HomeLen = -1; /* length of home directory string */
251:
252: #ifndef CHDIR
253:
254: char *
255: pr_name(fname, okay_home)
256: char *fname;
257: {
258: if (fname == 0)
259: return 0;
260:
261: if (okay_home == YES && strncmp(fname, HomeDir, HomeLen) == 0) {
262: static char name_buf[100];
263:
264: sprintf(name_buf, "~%s", fname + HomeLen);
265: return name_buf;
266: }
267:
268: return fname;
269: }
270:
271: #else
272:
273: #define NDIRS 5
274:
275: private char *DirStack[NDIRS] = {0};
276: private int DirSP = 0; /* Directory stack pointer */
277: #define PWD (DirStack[DirSP])
278:
279: char *
280: pwd()
281: {
282: return PWD;
283: }
284:
285: char *
286: pr_name(fname, okay_home)
287: char *fname;
288: {
289: int n;
290:
291: if (fname == 0)
292: return 0;
293: n = numcomp(fname, PWD);
294:
295: if ((PWD[n] == 0) && /* Matched to end of PWD */
296: (fname[n] == '/'))
297: return fname + n + 1;
298:
299: if (okay_home == YES && strcmp(HomeDir, "/") != 0 && strncmp(fname, HomeDir, HomeLen) == 0) {
300: static char name_buf[100];
301:
302: sprintf(name_buf, "~%s", fname + HomeLen);
303: return name_buf;
304: }
305:
306: return fname; /* return entire path name */
307: }
308:
309: extern unsigned int fmask;
310:
311: Chdir()
312: {
313: char dirbuf[FILESIZE];
314:
315: #ifdef MSDOS
316: fmask = 0x10;
317: #endif
318: (void) ask_file((char *) 0, PWD, dirbuf);
319: #ifdef MSDOS
320: fmask = 0x13;
321: if (Dchdir(dirbuf) == -1)
322: #else
323: if (chdir(dirbuf) == -1)
324: #endif
325: {
326: s_mess("cd: cannot change into %s.", dirbuf);
327: return;
328: }
329: UpdModLine = YES;
330: setCWD(dirbuf);
331: prCWD();
332: #ifdef MAC
333: Bufchange++;
334: #endif
335: }
336:
337: #ifdef UNIX
338: #ifndef JOB_CONTROL
339: char *
340: getwd(buffer)
341: char *buffer;
342: {
343: Buffer *old = curbuf;
344: char *ret_val;
345:
346: SetBuf(do_select((Window *) 0, "pwd-output"));
347: curbuf->b_type = B_PROCESS;
348: (void) UnixToBuf("pwd-output", NO, 0, YES, "/bin/pwd", (char *) 0);
349: ToFirst();
350: strcpy(buffer, linebuf);
351: SetBuf(old);
352: return buffer;
353: }
354: #endif
355: #endif /* UNIX */
356:
357: setCWD(d)
358: char *d;
359: {
360: if (PWD == 0)
361: PWD = malloc((unsigned) strlen(d) + 1);
362: else {
363: extern char *ralloc();
364:
365: PWD = ralloc(PWD, strlen(d) + 1);
366: }
367: strcpy(PWD, d);
368: }
369:
370: getCWD()
371: {
372: char *cwd;
373: char pathname[FILESIZE];
374: #if defined(UNIX) && defined(JOB_CONTROL)
375: extern char *getwd();
376: #endif
377: #if defined(MSDOS)
378: extern char *getcwd();
379: #endif
380:
381: #ifndef MSDOS
382: cwd = getenv("CWD");
383: if (cwd == 0)
384: cwd = getenv("PWD");
385: if (cwd == 0)
386: cwd = getwd(pathname);
387: #else /* MSDOS */
388: cwd = fixpath(getcwd(pathname, FILESIZE));
389: #endif /* MSDOS */
390:
391: setCWD(cwd);
392: }
393:
394: prDIRS()
395: {
396: register int i;
397:
398: s_mess(": %f ");
399: for (i = DirSP; i >= 0; i--)
400: add_mess("%s ", pr_name(DirStack[i], YES));
401: }
402:
403: prCWD()
404: {
405: s_mess(": %f => \"%s\"", PWD);
406: }
407:
408: Pushd()
409: {
410: char *newdir,
411: dirbuf[FILESIZE];
412:
413: #ifdef MSDOS
414: fmask = 0x10;
415: #endif
416: newdir = ask_file((char *) 0, NullStr, dirbuf);
417: #ifdef MSDOS
418: fmask = 0x13;
419: #endif
420: UpdModLine = YES;
421: if (*newdir == 0) { /* Wants to swap top two entries */
422: char *old_top;
423:
424: if (DirSP == 0)
425: complain("pushd: no other directory.");
426: old_top = PWD;
427: DirStack[DirSP] = DirStack[DirSP - 1];
428: DirStack[DirSP - 1] = old_top;
429: #ifdef MSDOS
430: (void) Dchdir(PWD);
431: #else
432: (void) chdir(PWD);
433: #endif
434: } else {
435: #ifdef MSDOS
436: if (Dchdir(dirbuf) == -1) {
437: #else
438: if (chdir(dirbuf) == -1) {
439: #endif
440: s_mess("pushd: cannot change into %s.", dirbuf);
441: return;
442: }
443:
444: if (DirSP + 1 >= NDIRS)
445: complain("pushd: full stack; max of %d pushes.", NDIRS);
446: DirSP += 1;
447: setCWD(dirbuf);
448: }
449: prDIRS();
450: }
451:
452: Popd()
453: {
454: if (DirSP == 0)
455: complain("popd: directory stack is empty.");
456: UpdModLine = YES;
457: free(PWD);
458: PWD = 0;
459: DirSP -= 1;
460: #ifdef MSDOS
461: (void) Dchdir(PWD); /* If this doesn't work, we's in deep shit. */
462: #else
463: (void) chdir(PWD); /* If this doesn't work, we's in deep shit. */
464: #endif
465: prDIRS();
466: }
467:
468: private char *
469: dbackup(base, offset, c)
470: register char *base,
471: *offset,
472: c;
473: {
474: while (offset > base && *--offset != c)
475: ;
476: return offset;
477: }
478:
479: private
480: dfollow(file, into)
481: char *file,
482: *into;
483: {
484: char *dp,
485: #ifdef MSDOS
486: filefix[FILESIZE],
487: #endif
488: *sp;
489:
490: #ifndef MSDOS
491: if (*file == '/') { /* Absolute pathname */
492: strcpy(into, "/");
493: file += 1;
494: } else
495: strcpy(into, PWD);
496: #else
497: abspath(file, filefix); /* convert to absolute pathname */
498: strcpy(into, filefix); /* and forget about drives */
499: into[3] = 0;
500: into = &(into[2]);
501: file = &(filefix[3]);
502: #endif
503: dp = into + strlen(into);
504:
505: sp = file;
506: do {
507: if (*file == 0)
508: break;
509: if (sp = index(file, '/'))
510: *sp = 0;
511: if (strcmp(file, ".") == 0)
512: ; /* So it will get to the end of the loop */
513: else if (strcmp(file, "..") == 0) {
514: *(dp = dbackup(into, dp, '/')) = 0;
515: if (dp == into)
516: strcpy(into, "/"), dp = into + 1;
517: } else {
518: if (into[strlen(into) - 1] != '/')
519: (void) strcat(into, "/"), dp += 1;
520: (void) strcat(into, file);
521: dp += strlen(file); /* stay at the end */
522: }
523: file = sp + 1;
524: } while (sp != 0);
525: }
526:
527: #endif /* CHDIR */
528:
529: #ifdef UNIX
530:
531: #ifdef !NOGETPWENT
532:
533: #include <pwd.h>
534: private
535: get_hdir(user, buf)
536: register char *user,
537: *buf;
538: {
539: register struct passwd *pw;
540:
541: setpwent();
542: while ((pw = getpwent()) != (struct passwd *)NULL)
543: if (strcmp(pw->pw_name, user) == 0) {
544: strncpy(buf, pw->pw_dir, FILESIZE);
545: buf[FILESIZE-1] = '\0';
546: endpwent();
547: return;
548: }
549: endpwent();
550: complain("[unknown user: %s]", user);
551: }
552:
553: #else /* NOGETPWENT */
554:
555: private
556: get_hdir(user, buf)
557: register char *user,
558: *buf;
559: {
560: char fbuf[LBSIZE],
561: pattern[100];
562: register int u_len;
563: File *fp;
564:
565: u_len = strlen(user);
566: fp = open_file("/etc/passwd", fbuf, F_READ, COMPLAIN, QUIET);
567: sprintf(pattern, "%s:[^:]*:[^:]*:[^:]*:[^:]*:\\([^:]*\\):", user);
568: while (f_gets(fp, genbuf, LBSIZE) != EOF)
569: if ((strncmp(genbuf, user, u_len) == 0) &&
570: (LookingAt(pattern, genbuf, 0))) {
571: putmatch(1, buf, FILESIZE);
572: close_file(fp);
573: return;
574: }
575: f_close(fp);
576: complain("[unknown user: %s]", user);
577: }
578:
579: #endif /* NOGETPWENT */
580: #endif /* UNIX */
581:
582: void
583: PathParse(name, intobuf)
584: char *name,
585: *intobuf;
586: {
587: char localbuf[FILESIZE];
588:
589: intobuf[0] = localbuf[0] = '\0';
590: if (*name == '\0')
591: return;
592: if (*name == '~') {
593: if (name[1] == '/' || name[1] == '\0') {
594: strcpy(localbuf, HomeDir);
595: name += 1;
596: #if !(defined(MSDOS) || defined(MAC)) /* may add for mac in future */
597: } else {
598: char *uendp = index(name, '/'),
599: unamebuf[30];
600:
601: if (uendp == 0)
602: uendp = name + strlen(name);
603: name = name + 1;
604: null_ncpy(unamebuf, name, uendp - name);
605: get_hdir(unamebuf, localbuf);
606: name = uendp;
607: #endif
608: }
609: }
610: #ifndef MSDOS
611: else if (*name == '\\')
612: name += 1;
613: #endif /* MSDOS */
614: (void) strcat(localbuf, name);
615: #ifdef CHDIR
616: dfollow(localbuf, intobuf);
617: #else
618: strcpy(intobuf, localbuf);
619: #endif
620: }
621:
622: void
623: filemunge(newname)
624: char *newname;
625: {
626: struct stat stbuf;
627:
628: if (newname == 0)
629: return;
630: if (stat(newname, &stbuf))
631: return;
632: #ifndef MSDOS
633: if (((stbuf.st_dev != curbuf->b_dev) ||
634: (stbuf.st_ino != curbuf->b_ino)) &&
635: #else /* MSDOS */
636: if ( /* (stbuf.st_ino != curbuf->b_ino) && */
637: #endif /* MSDOS */
638: #ifndef MAC
639: ((stbuf.st_mode & S_IFMT) != S_IFCHR) &&
640: #endif
641: (strcmp(newname, curbuf->b_fname) != 0)) {
642: rbell();
643: confirm("\"%s\" already exists; overwrite it? ", newname);
644: }
645: }
646:
647: void
648: WrtReg()
649: {
650: DoWriteReg(NO);
651: }
652:
653: void
654: AppReg()
655: {
656: DoWriteReg(YES);
657: }
658:
659: int CreatMode = DFLT_MODE;
660:
661: void
662: DoWriteReg(app)
663: {
664: char fnamebuf[FILESIZE],
665: *fname;
666: Mark *mp = CurMark();
667: File *fp;
668:
669: /* Won't get here if there isn't a Mark */
670: fname = ask_file((char *) 0, (char *) 0, fnamebuf);
671:
672: #ifdef BACKUPFILES
673: if (app == NO) {
674: filemunge(fname);
675:
676: if (BkupOnWrite)
677: file_backup(fname);
678: }
679: #else
680: if (!app)
681: filemunge(fname);
682: #endif
683:
684: fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, COMPLAIN, !QUIET);
685: putreg(fp, mp->m_line, mp->m_char, curline, curchar, YES);
686: close_file(fp);
687: }
688:
689: int OkayBadChars = 0;
690:
691: void
692: WriteFile()
693: {
694: char *fname,
695: fnamebuf[FILESIZE];
696: #ifdef MAC
697: if (Macmode) {
698: if(!(fname = pfile(fnamebuf))) return;
699: }
700: else
701: #endif /* MAC */
702:
703: fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf);
704: /* Don't allow bad characters when creating new files. */
705: if (!OkayBadChars && strcmp(curbuf->b_fname, fnamebuf) != 0) {
706: #ifdef UNIX
707: static char *badchars = "!$^&*()~`{}\"'\\|<>? ";
708: #endif /* UNIX */
709: #ifdef MSDOS
710: static char *badchars = "*|<>? ";
711: #endif /* MSDOS */
712: #ifdef MAC
713: static char *badchars = ":";
714: #endif /* MAC */
715: register char *cp = fnamebuf;
716: register int c;
717:
718: while (c = *cp++ & CHARMASK) /* avoid sign extension... */
719: if (c < ' ' || c == '\177' || index(badchars, c))
720: complain("'%p': bad character in filename.", c);
721: }
722:
723: #ifndef MAC
724: #ifndef MSDOS
725: chk_mtime(curbuf, fname, "write");
726: #endif /* MSDOS */
727: #endif /* MAC */
728: filemunge(fname);
729: curbuf->b_type = B_FILE; /* in case it wasn't before */
730: setfname(curbuf, fname);
731: file_write(fname, 0);
732: unmodify();
733: }
734:
735: /* Open file FNAME supplying the buffer IO routine with buffer BUF.
736: HOW is F_READ, F_WRITE or F_APPEND. IFBAD == COMPLAIN means that
737: if we fail at opening the file, call complain. LOUDNESS says
738: whether or not to print the "reading ..." message on the message
739: line.
740:
741: NOTE: This opens the pr_name(fname, NO) of fname. That is, FNAME
742: is usually an entire pathname, which can be slow when the
743: pathname is long and there are lots of symbolic links along
744: the way (which has become very common in my experience). So,
745: this speeds up opens file names in the local directory. It
746: will not speed up things like "../scm/foo.scm" simple because
747: by the time we get here that's already been expanded to an
748: absolute pathname. But this is a start.
749: */
750:
751: File *
752: open_file(fname, buf, how, ifbad, loudness)
753: register char *fname;
754: char *buf;
755: register int how;
756: {
757: register File *fp;
758:
759: io_chars = 0;
760: io_lines = 0;
761:
762: fp = f_open(pr_name(fname, NO), how, buf, LBSIZE);
763: if (fp == NIL) {
764: message(IOerr((how == F_READ) ? "open" : "create", fname));
765: if (ifbad == COMPLAIN)
766: complain((char *) 0);
767: } else {
768: int readonly = FALSE;
769: #ifndef MAC
770: if (access(pr_name(fname, NO), W_OK) == -1 && errno != ENOENT)
771: readonly = TRUE;
772: #endif
773: if (loudness != QUIET) {
774: fp->f_flags |= F_TELLALL;
775: f_mess("\"%s\"%s", pr_name(fname, YES),
776: readonly ? " [Read only]" : NullStr);
777: }
778: }
779: return fp;
780: }
781:
782: #ifndef MSDOS
783: /* Check to see if the file has been modified since it was
784: last written. If so, make sure they know what they're
785: doing.
786:
787: I hate to use another stat(), but to use confirm we gotta
788: do this before we open the file.
789:
790: NOTE: This stats FNAME after converting it to a path-relative
791: name. I can't see why this would cause a problem ...
792: */
793:
794: chk_mtime(thisbuf, fname, how)
795: Buffer *thisbuf;
796: char *fname,
797: *how;
798: {
799: struct stat stbuf;
800: Buffer *b;
801: char *mesg = "Shall I go ahead and %s anyway? ";
802:
803: if ((thisbuf->b_mtime != 0) && /* if we care ... */
804: (b = file_exists(fname)) && /* we already have this file */
805: (b == thisbuf) && /* and it's the current buffer */
806: (stat(pr_name(fname, NO), &stbuf) != -1) && /* and we can stat it */
807: (stbuf.st_mtime != b->b_mtime)) { /* and there's trouble. */
808: rbell();
809: redisplay(); /* Ring that bell! */
810: TOstart("Warning", TRUE);
811: Typeout("\"%s\" now saved on disk is not what you last", pr_name(fname, YES));
812: Typeout("visited or saved. Probably someone else is editing");
813: Typeout("your file at the same time.");
814: if (how) {
815: Typeout("");
816: Typeout("Type \"y\" if I should %s, anyway.", how);
817: f_mess(mesg, how);
818: }
819: TOstop();
820: if (how)
821: confirm(mesg, how);
822: }
823: }
824:
825: #endif /* MSDOS */
826:
827: void
828: file_write(fname, app)
829: char *fname;
830: {
831: File *fp;
832:
833: #ifdef BACKUPFILES
834: if (!app && BkupOnWrite)
835: file_backup(fname);
836: #endif
837:
838: fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, COMPLAIN, !QUIET);
839:
840: if (EndWNewline) { /* Make sure file ends with a newLine */
841: Bufpos save;
842:
843: DOTsave(&save);
844: ToLast();
845: if (length(curline)) /* Not a blank Line */
846: LineInsert(1);
847: SetDot(&save);
848: }
849: putreg(fp, curbuf->b_first, 0, curbuf->b_last, length(curbuf->b_last), NO);
850: set_ino(curbuf);
851: close_file(fp);
852: }
853:
854: void
855: ReadFile()
856: {
857: Buffer *bp;
858: char *fname,
859: fnamebuf[FILESIZE];
860: int lineno;
861:
862: #ifdef MAC
863: if(Macmode) {
864: if(!(fname = gfile(fnamebuf))) return;
865: }
866: else
867: #endif /* MAC */
868: fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf);
869: #if !(defined(MSDOS) || defined(MAC))
870: chk_mtime(curbuf, fname, "read");
871: #endif /* MSDOS || MAC */
872:
873: if (IsModified(curbuf)) {
874: char *y_or_n;
875: int c;
876:
877: for (;;) {
878: rbell();
879: y_or_n = ask(NullStr, "Shall I make your changes to \"%s\" permanent? ", curbuf->b_name);
880: c = CharUpcase(*y_or_n);
881: if (c == 'Y' || c == 'N')
882: break;
883: }
884: if (c == 'Y')
885: SaveFile();
886: }
887:
888: if ((bp = file_exists(fnamebuf)) &&
889: (bp == curbuf))
890: lineno = pnt_line() - 1;
891: else
892: lineno = 0;
893:
894: unmodify();
895: initlist(curbuf);
896: setfname(curbuf, fname);
897: read_file(fname, 0);
898: SetLine(next_line(curbuf->b_first, lineno));
899: }
900:
901: void
902: InsFile()
903: {
904: char *fname,
905: fnamebuf[FILESIZE];
906: #ifdef MAC
907: if(Macmode) {
908: if(!(fname = gfile(fnamebuf))) return;
909: }
910: else
911: #endif /* MAC */
912: fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf);
913: read_file(fname, 1);
914: }
915:
916: #include "temp.h"
917:
918: int DOLsave = 0; /* Do Lsave flag. If lines aren't being save
919: when you think they should have been, this
920: flag is probably not being set, or is being
921: cleared before lsave() was called. */
922:
923: private int nleft, /* number of good characters left in current block */
924: tmpfd = -1;
925: disk_line DFree = 1;
926: /* pointer to end of tmp file */
927: private char *tfname;
928:
929: void
930: tmpinit()
931: {
932: char buf[FILESIZE];
933:
934: #ifdef MAC
935: sprintf(buf, "%s/%s", HomeDir, d_tempfile);
936: #else
937: sprintf(buf, "%s/%s", TmpFilePath, d_tempfile);
938: #endif
939: tfname = copystr(buf);
940: tfname = mktemp(tfname);
941: (void) close(creat(tfname, 0600));
942: #ifndef MSDOS
943: tmpfd = open(tfname, 2);
944: #else /* MSDOS */
945: tmpfd = open(tfname, 0x8002); /* MSDOS fix */
946: #endif /* MSDOS */
947: if (tmpfd == -1)
948: complain("Warning: cannot create tmp file!");
949: }
950:
951: void
952: tmpclose()
953: {
954: if (tmpfd == -1)
955: return;
956: (void) close(tmpfd);
957: tmpfd = -1;
958: (void) unlink(tfname);
959: }
960:
961: /* get a line at `tl' in the tmp file into `buf' which should be LBSIZE
962: long */
963:
964: int Jr_Len; /* length of Just Read Line */
965:
966: #ifdef MAC /* The Lighspeed compiler can't copy with static here */
967: char *getblock();
968: #else
969: private char *getblock();
970: #endif
971: void
972: getline(addr, buf)
973: disk_line addr;
974: register char *buf;
975: {
976: register char *bp,
977: *lp;
978:
979: lp = buf;
980: bp = getblock(addr >> 1, READ);
981: while (*lp++ = *bp++)
982: ;
983: Jr_Len = (lp - buf) - 1;
984: }
985:
986: /* Put `buf' and return the disk address */
987:
988: disk_line
989: putline(buf)
990: char *buf;
991: {
992: register char *bp,
993: *lp;
994: register int nl;
995: disk_line free_ptr;
996:
997: lp = buf;
998: free_ptr = DFree;
999: bp = getblock(free_ptr, WRITE);
1000: nl = nleft;
1001: free_ptr = blk_round(free_ptr);
1002: while (*bp = *lp++) {
1003: if (*bp++ == '\n') {
1004: *--bp = 0;
1005: break;
1006: }
1007: if (--nl == 0) {
1008: free_ptr = forward_block(free_ptr);
1009: DFree = free_ptr;
1010: bp = getblock(free_ptr, WRITE);
1011: lp = buf; /* start over ... */
1012: nl = nleft;
1013: }
1014: }
1015: free_ptr = DFree;
1016: DFree += (((lp - buf) + CH_SIZE - 1) / CH_SIZE);
1017: /* (lp - buf) includes the null */
1018: return (free_ptr << 1);
1019: }
1020:
1021: /* The theory is that critical section of code inside this procedure
1022: will never cause a problem to occur. Basically, we need to ensure
1023: that two blocks are in memory at the same time, but I think that
1024: this can never screw up. */
1025:
1026: #define lockblock(addr)
1027: #define unlockblock(addr)
1028:
1029: disk_line
1030: f_getputl(line, fp)
1031: Line *line;
1032: register File *fp;
1033: {
1034: register char *bp;
1035: register int c,
1036: nl,
1037: max = LBSIZE;
1038: disk_line free_ptr;
1039: char *base;
1040: #ifdef MSDOS
1041: char crleft = 0;
1042: #endif /* MSDOS */
1043:
1044: free_ptr = DFree;
1045: base = bp = getblock(free_ptr, WRITE);
1046: nl = nleft;
1047: free_ptr = blk_round(free_ptr);
1048: while (--max > 0) {
1049: #ifdef MSDOS
1050: if (crleft) {
1051: c = crleft;
1052: crleft = 0;
1053: } else
1054: #endif /* MSDOS */
1055: c = getc(fp);
1056: if (c == EOF || c == '\n')
1057: break;
1058: #ifdef MSDOS
1059: if (c == '\r')
1060: if ((crleft = getc(fp)) == '\n') {
1061: crleft = 0;
1062: break;
1063: }
1064: #endif /* MSDOS */
1065: if (--nl == 0) {
1066: char *newbp;
1067: int nbytes;
1068:
1069: lockblock(free_ptr);
1070: DFree = free_ptr = forward_block(free_ptr);
1071: nbytes = bp - base;
1072: newbp = getblock(free_ptr, WRITE);
1073: nl = nleft;
1074: byte_copy(base, newbp, nbytes);
1075: bp = newbp + nbytes;
1076: base = newbp;
1077: unlockblock(free_ptr);
1078: }
1079: *bp++ = c;
1080: }
1081: *bp++ = '\0';
1082: free_ptr = DFree;
1083: DFree += (((bp - base) + CH_SIZE - 1) / CH_SIZE);
1084: line->l_dline = (free_ptr << 1);
1085: if (max == 0) {
1086: add_mess(" [Line too long]");
1087: rbell();
1088: return EOF;
1089: }
1090: if (c == EOF) {
1091: if (--bp != base)
1092: add_mess(" [Incomplete last line]");
1093: return EOF;
1094: }
1095: io_lines += 1;
1096: return 0;
1097: }
1098:
1099: typedef struct block {
1100: short b_dirty,
1101: b_bno;
1102: char b_buf[BUFSIZ];
1103: struct block
1104: *b_LRUnext,
1105: *b_LRUprev,
1106: *b_HASHnext;
1107: } Block;
1108:
1109: #define HASHSIZE 7 /* Primes work best (so I'm told) */
1110: #define B_HASH(bno) (bno % HASHSIZE)
1111:
1112: #ifdef MAC
1113: private Block *b_cache,
1114: #else
1115: private Block b_cache[NBUF],
1116: #endif
1117: *bht[HASHSIZE] = {0}, /* Block hash table */
1118: *f_block = 0,
1119: *l_block = 0;
1120: private int max_bno = -1,
1121: NBlocks;
1122:
1123: #ifdef MAC
1124: void (*blkio)();
1125: #else
1126: #ifdef LINT_ARGS
1127: private int (*blkio)(Block *, int (*)());
1128: #else
1129: private int (*blkio)();
1130: #endif
1131: #endif /* MAC */
1132:
1133: #ifdef MAC
1134: make_cache() /* Only 32K of static space on Mac, so... */
1135: {
1136: return((b_cache = (Block *) calloc(NBUF,sizeof(Block))) == 0 ? 0 : 1);
1137: }
1138: #endif /* MAC */
1139:
1140: extern int read(), write();
1141:
1142: private void
1143: real_blkio(b, iofcn)
1144: register Block *b;
1145: #ifdef MAC
1146: register int (*iofcn)();
1147: #else
1148: #ifdef LINT_ARGS
1149: register int (*iofcn)(int, char *, unsigned int);
1150: #else
1151: register int (*iofcn)();
1152: #endif
1153: #endif /* MAC */
1154: {
1155: (void) lseek(tmpfd, (long) ((unsigned) b->b_bno) * BUFSIZ, 0);
1156: if ((*iofcn)(tmpfd, b->b_buf, BUFSIZ) != BUFSIZ)
1157: error("[Tmp file %s error; to continue editing would be dangerous]", (iofcn == read) ? "READ" : "WRITE");
1158: }
1159:
1160: private void
1161: fake_blkio(b, iofcn)
1162: register Block *b;
1163: register int (*iofcn)();
1164: {
1165: tmpinit();
1166: blkio = real_blkio;
1167: real_blkio(b, iofcn);
1168: }
1169:
1170: void
1171: d_cache_init()
1172: {
1173: register Block *bp, /* Block pointer */
1174: **hp; /* Hash pointer */
1175: register short bno;
1176:
1177: for (bp = b_cache, bno = NBUF; --bno >= 0; bp++) {
1178: NBlocks += 1;
1179: bp->b_dirty = 0;
1180: bp->b_bno = bno;
1181: if (l_block == 0)
1182: l_block = bp;
1183: bp->b_LRUprev = 0;
1184: bp->b_LRUnext = f_block;
1185: if (f_block != 0)
1186: f_block->b_LRUprev = bp;
1187: f_block = bp;
1188:
1189: bp->b_HASHnext = *(hp = &bht[B_HASH(bno)]);
1190: *hp = bp;
1191: }
1192: blkio = fake_blkio;
1193: }
1194:
1195: void
1196: SyncTmp()
1197: {
1198: register Block *b;
1199: #ifdef IBMPC
1200: register int bno = 0;
1201: Block *lookup();
1202:
1203: /* sync the blocks in order, for floppy disks */
1204: for (bno = 0; bno <= max_bno; ) {
1205: if ((b = lookup(bno++)) && b->b_dirty) {
1206: (*blkio)(b, write);
1207: b->b_dirty = 0;
1208: }
1209: }
1210: #else
1211: for (b = f_block; b != 0; b = b->b_LRUnext)
1212: if (b->b_dirty) {
1213: (*blkio)(b, write);
1214: b->b_dirty = 0;
1215: }
1216: #endif
1217: }
1218:
1219: private Block *
1220: lookup(bno)
1221: register short bno;
1222: {
1223: register Block *bp;
1224:
1225: for (bp = bht[B_HASH(bno)]; bp != 0; bp = bp->b_HASHnext)
1226: if (bp->b_bno == bno)
1227: break;
1228: return bp;
1229: }
1230:
1231: private void
1232: LRUunlink(b)
1233: register Block *b;
1234: {
1235: if (b->b_LRUprev == 0)
1236: f_block = b->b_LRUnext;
1237: else
1238: b->b_LRUprev->b_LRUnext = b->b_LRUnext;
1239: if (b->b_LRUnext == 0)
1240: l_block = b->b_LRUprev;
1241: else
1242: b->b_LRUnext->b_LRUprev = b->b_LRUprev;
1243: }
1244:
1245: private Block *
1246: b_unlink(bp)
1247: register Block *bp;
1248: {
1249: register Block *hp,
1250: *prev = 0;
1251:
1252: LRUunlink(bp);
1253: /* Now that we have the block, we remove it from its position
1254: in the hash table, so we can THEN put it somewhere else with
1255: it's new block assignment. */
1256:
1257: for (hp = bht[B_HASH(bp->b_bno)]; hp != 0; prev = hp, hp = hp->b_HASHnext)
1258: if (hp == bp)
1259: break;
1260: if (hp == 0) {
1261: printf("\rBlock %d missing!", bp->b_bno);
1262: finish(0);
1263: }
1264: if (prev)
1265: prev->b_HASHnext = hp->b_HASHnext;
1266: else
1267: bht[B_HASH(bp->b_bno)] = hp->b_HASHnext;
1268:
1269: if (bp->b_dirty) { /* do, now, the delayed write */
1270: (*blkio)(bp, write);
1271: bp->b_dirty = 0;
1272: }
1273:
1274: return bp;
1275: }
1276:
1277: /* Get a block which contains at least part of the line with the address
1278: atl. Returns a pointer to the block and sets the global variable
1279: nleft (number of good characters left in the buffer). */
1280:
1281: private char *
1282: getblock(atl, iof)
1283: disk_line atl;
1284: {
1285: register int bno,
1286: off;
1287: register Block *bp;
1288: static Block *lastb = 0;
1289:
1290: bno = da_to_bno(atl);
1291: off = da_to_off(atl);
1292: if (da_too_huge(atl))
1293: error("Tmp file too large. Get help!");
1294: nleft = BUFSIZ - off;
1295: if (lastb != 0 && lastb->b_bno == bno) {
1296: lastb->b_dirty |= iof;
1297: return lastb->b_buf + off;
1298: }
1299:
1300: /* The requested block already lives in memory, so we move
1301: it to the end of the LRU list (making it Most Recently Used)
1302: and then return a pointer to it. */
1303: if (bp = lookup(bno)) {
1304: if (bp != l_block) {
1305: LRUunlink(bp);
1306: if (l_block == 0)
1307: f_block = l_block = bp;
1308: else
1309: l_block->b_LRUnext = bp;
1310: bp->b_LRUprev = l_block;
1311: l_block = bp;
1312: bp->b_LRUnext = 0;
1313: }
1314: if (bp->b_bno > max_bno)
1315: max_bno = bp->b_bno;
1316: bp->b_dirty |= iof;
1317: lastb = bp;
1318: return bp->b_buf + off;
1319: }
1320:
1321: /* The block we want doesn't reside in memory so we take the
1322: least recently used clean block (if there is one) and use
1323: it. */
1324: bp = f_block;
1325: if (bp->b_dirty) /* The best block is dirty ... */
1326: SyncTmp();
1327:
1328: bp = b_unlink(bp);
1329: if (l_block == 0)
1330: l_block = f_block = bp;
1331: else
1332: l_block->b_LRUnext = bp; /* Place it at the end ... */
1333: bp->b_LRUprev = l_block;
1334: l_block = bp;
1335: bp->b_LRUnext = 0; /* so it's Most Recently Used */
1336:
1337: bp->b_dirty = iof;
1338: bp->b_bno = bno;
1339: bp->b_HASHnext = bht[B_HASH(bno)];
1340: bht[B_HASH(bno)] = bp;
1341:
1342: /* Get the current contents of the block UNLESS this is a new
1343: block that's never been looked at before, i.e., it's past
1344: the end of the tmp file. */
1345:
1346: if (bp->b_bno <= max_bno)
1347: (*blkio)(bp, read);
1348: else
1349: max_bno = bno;
1350:
1351: lastb = bp;
1352: return bp->b_buf + off;
1353: }
1354:
1355: char *
1356: lbptr(line)
1357: Line *line;
1358: {
1359: return getblock(line->l_dline >> 1, READ);
1360: }
1361:
1362: /* save the current contents of linebuf, if it has changed */
1363:
1364: void
1365: lsave()
1366: {
1367: if (curbuf == 0 || !DOLsave) /* Nothing modified recently */
1368: return;
1369:
1370: if (strcmp(lbptr(curline), linebuf) != 0)
1371: SavLine(curline, linebuf); /* Put linebuf on the disk. */
1372: DOLsave = 0;
1373: }
1374:
1375: #ifdef BACKUPFILES
1376: void
1377: file_backup(fname)
1378: char *fname;
1379: {
1380: #ifndef MSDOS
1381: char *s;
1382: register int i;
1383: int fd1,
1384: fd2;
1385: char tmp1[BUFSIZ],
1386: tmp2[BUFSIZ];
1387: struct stat buf;
1388: int mode;
1389:
1390: strcpy(tmp1, fname);
1391: if ((s = rindex(tmp1, '/')) == NULL)
1392: sprintf(tmp2, "#%s", fname);
1393: else {
1394: *s++ = '\0';
1395: sprintf(tmp2, "%s/#%s", tmp1, s);
1396: }
1397:
1398: if ((fd1 = open(fname, 0)) < 0)
1399: return;
1400:
1401: /* create backup file with same mode as input file */
1402: #ifndef MAC
1403: if (fstat(fd1, &buf) != 0)
1404: mode = CreatMode;
1405: else
1406: #endif
1407: mode = buf.st_mode;
1408:
1409: if ((fd2 = creat(tmp2, mode)) < 0) {
1410: (void) close(fd1);
1411: return;
1412: }
1413: while ((i = read(fd1, tmp1, sizeof(tmp1))) > 0)
1414: write(fd2, tmp1, i);
1415: #ifdef BSD4_2
1416: (void) fsync(fd2);
1417: #endif
1418: (void) close(fd2);
1419: (void) close(fd1);
1420: #else /* MSDOS */
1421: char *dot,
1422: *slash,
1423: tmp[FILESIZE];
1424:
1425: strcpy(tmp, fname);
1426: slash = basename(tmp);
1427: if (dot = rindex(slash, '.')) {
1428: if (!stricmp(dot,".bak"))
1429: return;
1430: else *dot = 0;
1431: }
1432: strcat(tmp, ".bak");
1433: unlink(tmp);
1434: rename(fname, tmp);
1435: #endif /* MSDOS */
1436: }
1437: #endif
1438:
1439: #if defined(MSDOS) && defined (CHDIR)
1440:
1441: private int /* chdir + drive */
1442: Dchdir(to)
1443: char *to;
1444: {
1445: unsigned d, dd, n;
1446:
1447: if (to[1] == ':') {
1448: d = to[0];
1449: if (d >= 'a') d = d - 'a' + 1;
1450: if (d >= 'A') d = d - 'A' + 1;
1451: _dos_getdrive(&dd);
1452: if (dd != d)
1453: _dos_setdrive(d, &n);
1454: if (to[2] == 0)
1455: return 0;
1456: }
1457: return chdir(to);
1458: }
1459:
1460: private char *
1461: fixpath(p)
1462: char *p;
1463: {
1464: char *pp = p;
1465:
1466: while (*p) {
1467: if (*p == '\\')
1468: *p = '/';
1469: p++;
1470: }
1471: return(strlwr(pp));
1472: }
1473:
1474:
1475: private void
1476: abspath(so, dest)
1477: char *so, *dest;
1478: {
1479: char cwd[FILESIZE], cwdD[3], cwdDIR[FILESIZE], cwdF[9], cwdEXT[5],
1480: soD[3], soDIR[FILESIZE], soF[9], soEXT[5];
1481: char *drive, *path;
1482:
1483: _splitpath(fixpath(so), soD, soDIR, soF, soEXT);
1484: getcwd(cwd, FILESIZE);
1485: if (*soD != 0) {
1486: Dchdir(soD); /* this is kinda messy */
1487: getcwd(cwdDIR, FILESIZE); /* should probably just */
1488: Dchdir(cwd); /* call DOS to do it */
1489: strcpy(cwd, cwdDIR);
1490: }
1491: (void) fixpath(cwd);
1492: if (cwd[strlen(cwd)-1] != '/')
1493: strcat(cwd, "/x.x"); /* need dummy filename */
1494:
1495: _splitpath(fixpath(cwd), cwdD, cwdDIR, cwdF, cwdEXT);
1496:
1497: drive = (*soD == 0) ? cwdD : soD;
1498:
1499: if (*soDIR != '/')
1500: path = strcat(cwdDIR, soDIR);
1501: else
1502: path = soDIR;
1503: _makepath(dest, drive, path, soF, soEXT);
1504: fixpath(dest); /* can't do it often enough */
1505: }
1506:
1507: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.