|
|
1.1 root 1: /*************************************************************************
2: * This program is copyright (C) 1985, 1986 by Jonathan Payne. It is *
3: * provided to you without charge for use only on a licensed Unix *
4: * system. You may copy JOVE provided that this notice is included with *
5: * the copy. You may not sell copies of this program or versions *
6: * modified for use on microcomputer systems, unless the copies are *
7: * included with a Unix system distribution and the source is provided. *
8: *************************************************************************/
9:
10: #include "jove.h"
11: #include "io.h"
12: #include "termcap.h"
13:
14: #ifdef IPROCS
15: # include <signal.h>
16: #endif
17:
18: #include <sys/stat.h>
19: #include <sys/file.h>
20: #include <errno.h>
21:
22: long io_chars; /* number of chars in this open_file */
23: int io_lines; /* number of lines in this open_file */
24: private int tellall; /* display file io info? */
25:
26: #ifdef VMUNIX
27: char iobuff[LBSIZE],
28: genbuf[LBSIZE],
29: linebuf[LBSIZE];
30: #else
31: char *iobuff,
32: *genbuf,
33: *linebuf;
34: #endif
35:
36: #ifdef BACKUPFILES
37: int BkupOnWrite = 0;
38: #endif
39:
40: close_file(fp)
41: File *fp;
42: {
43: if (fp) {
44: f_close(fp);
45: if (tellall != QUIET)
46: add_mess(" %d lines, %D characters.",
47: io_lines,
48: io_chars);
49: }
50: }
51:
52: /* Write the region from line1/char1 to line2/char2 to FP. This
53: never CLOSES the file since we don't know if we want to. */
54:
55: int EndWNewline = 1;
56:
57: putreg(fp, line1, char1, line2, char2, makesure)
58: register File *fp;
59: Line *line1,
60: *line2;
61: {
62: register int c;
63: register char *lp;
64:
65: if (makesure)
66: (void) fixorder(&line1, &char1, &line2, &char2);
67: while (line1 != line2->l_next) {
68: lp = lcontents(line1) + char1;
69: if (line1 == line2)
70: fputnchar(lp, (char2 - char1), fp);
71: else while (c = *lp++) {
72: putc(c, fp);
73: io_chars++;
74: }
75: if (line1 != line2) {
76: io_lines++;
77: io_chars++;
78: putc('\n', fp);
79: }
80: line1 = line1->l_next;
81: char1 = 0;
82: }
83: flush(fp);
84: }
85:
86: read_file(file, is_insert)
87: char *file;
88: {
89: Bufpos save;
90: File *fp;
91:
92: if (!is_insert) {
93: curbuf->b_ntbf = 0;
94: set_ino(curbuf);
95: }
96: fp = open_file(file, iobuff, F_READ, !COMPLAIN, !QUIET);
97: if (fp == NIL) {
98: if (!is_insert && errno == ENOENT)
99: s_mess("(new file)");
100: else
101: s_mess(IOerr("open", file));
102: return;
103: }
104: DOTsave(&save);
105: dofread(fp);
106: SetDot(&save);
107: if (is_insert && io_chars > 0)
108: modify();
109: getDOT();
110: close_file(fp);
111: }
112:
113: dofread(fp)
114: register File *fp;
115: {
116: char end[LBSIZE];
117: int xeof = 0;
118: Line *savel = curline;
119: int savec = curchar;
120:
121: strcpy(end, linebuf + curchar);
122: xeof = f_gets(fp, linebuf + curchar, LBSIZE - curchar);
123: SavLine(curline, linebuf);
124: if (!xeof) do {
125: xeof = f_gets(fp, linebuf, LBSIZE);
126: curline = listput(curbuf, curline);
127: curline->l_dline = putline(linebuf) | DIRTY;
128: } while (!xeof);
129: linecopy(linebuf, (curchar = strlen(linebuf)), end);
130: SavLine(curline, linebuf);
131: IFixMarks(savel, savec, curline, curchar);
132: }
133:
134: SaveFile()
135: {
136: if (IsModified(curbuf)) {
137: if (curbuf->b_fname == 0)
138: WriteFile();
139: else {
140: filemunge(curbuf->b_fname);
141: chk_mtime(curbuf->b_fname, "save");
142: file_write(curbuf->b_fname, 0);
143: unmodify();
144: }
145: } else
146: message("No changes need to be written.");
147: }
148:
149: char *HomeDir; /* home directory */
150: int HomeLen = -1; /* length of home directory string */
151:
152: #ifndef CHDIR
153:
154: char *
155: pr_name(fname)
156: char *fname;
157: {
158: if (fname == 0)
159: return 0;
160:
161: if (strncmp(fname, HomeDir, HomeLen) == 0) {
162: static char name_buf[100];
163:
164: sprintf(name_buf, "~%s", fname + HomeLen);
165: return name_buf;
166: }
167:
168: return fname;
169: }
170:
171: #else
172:
173: #define NDIRS 5
174:
175: private char *DirStack[NDIRS] = {0};
176: private int DirSP = 0; /* Directory stack pointer */
177: #define PWD (DirStack[DirSP])
178:
179: char *
180: pwd()
181: {
182: return PWD;
183: }
184:
185: char *
186: pr_name(fname)
187: char *fname;
188: {
189: int n;
190:
191: if (fname == 0)
192: return 0;
193: n = numcomp(fname, PWD);
194:
195: if ((PWD[n] == 0) && /* Matched to end of PWD */
196: (fname[n] == '/'))
197: return fname + n + 1;
198:
199: if (strcmp(HomeDir, "/") != 0 && strncmp(fname, HomeDir, HomeLen) == 0) {
200: static char name_buf[100];
201:
202: sprintf(name_buf, "~%s", fname + HomeLen);
203: return name_buf;
204: }
205:
206: return fname; /* return entire path name */
207: }
208:
209: Chdir()
210: {
211: char dirbuf[FILESIZE];
212:
213: (void) ask_file(PWD, dirbuf);
214: if (chdir(dirbuf) == -1) {
215: s_mess("cd: cannot change into %s.", dirbuf);
216: return;
217: }
218: UpdModLine++;
219: setCWD(dirbuf);
220: }
221:
222: #ifndef JOB_CONTROL
223: char *
224: getwd()
225: {
226: Buffer *old = curbuf;
227: char *ret_val;
228:
229: SetBuf(do_select((Window *) 0, "pwd-output"));
230: curbuf->b_type = B_PROCESS;
231: (void) UnixToBuf("pwd-output", NO, 0, YES, "/bin/pwd", "pwd", 0);
232: ToFirst();
233: ret_val = sprint(linebuf);
234: SetBuf(old);
235: return ret_val;
236: }
237: #endif
238:
239: setCWD(d)
240: char *d;
241: {
242: if (PWD == 0)
243: PWD = malloc((unsigned) strlen(d) + 1);
244: else {
245: extern char *ralloc();
246:
247: PWD = ralloc(PWD, strlen(d) + 1);
248: }
249: strcpy(PWD, d);
250: }
251:
252: getCWD()
253: {
254: char *cwd = getenv("CWD");
255: #ifdef JOB_CONTROL
256: extern char *getwd();
257: char pathname[FILESIZE];
258: #endif
259:
260: if (cwd == 0)
261: #ifdef JOB_CONTROL
262: cwd = getwd(pathname);
263: #else
264: cwd = getwd();
265: #endif
266:
267: setCWD(cwd);
268: }
269:
270: prDIRS()
271: {
272: register int i;
273:
274: s_mess(": %f ");
275: for (i = DirSP; i >= 0; i--)
276: add_mess("%s ", pr_name(DirStack[i]));
277: }
278:
279: prCWD()
280: {
281: s_mess(": %f => \"%s\"", PWD);
282: }
283:
284: Pushd()
285: {
286: char *newdir,
287: dirbuf[FILESIZE];
288:
289: newdir = ask_file(NullStr, dirbuf); /* Parses directories ... */
290: UpdModLine++;
291: if (*newdir == 0) { /* Wants to swap top two entries */
292: char *old_top;
293:
294: if (DirSP == 0)
295: complain("pushd: no other directory.");
296: old_top = PWD;
297: DirStack[DirSP] = DirStack[DirSP - 1];
298: DirStack[DirSP - 1] = old_top;
299: (void) chdir(PWD);
300: } else {
301: if (chdir(dirbuf) == -1) {
302: s_mess("pushd: cannot change into %s.", dirbuf);
303: return;
304: }
305:
306: if (DirSP + 1 >= NDIRS)
307: complain("pushd: full stack; max of %d pushes.", NDIRS);
308: DirSP++;
309: setCWD(dirbuf);
310: }
311: prDIRS();
312: }
313:
314: Popd()
315: {
316: if (DirSP == 0)
317: complain("popd: directory stack is empty.");
318: UpdModLine++;
319: free(PWD);
320: PWD = 0;
321: DirSP--;
322: (void) chdir(PWD); /* If this doesn't work, we's in deep shit. */
323: prDIRS();
324: }
325:
326: private char *
327: dbackup(base, offset, c)
328: register char *base,
329: *offset,
330: c;
331: {
332: while (offset > base && *--offset != c)
333: ;
334: return offset;
335: }
336:
337: dfollow(file, into)
338: char *file,
339: *into;
340: {
341: char *dp,
342: *sp;
343:
344: if (*file == '/') { /* Absolute pathname */
345: strcpy(into, "/");
346: file++;
347: } else
348: strcpy(into, PWD);
349: dp = into + strlen(into);
350:
351: sp = file;
352: do {
353: if (*file == 0)
354: break;
355: if (sp = index(file, '/'))
356: *sp = 0;
357: if (strcmp(file, ".") == 0)
358: ; /* So it will get to the end of the loop */
359: else if (strcmp(file, "..") == 0) {
360: *(dp = dbackup(into, dp, '/')) = 0;
361: if (dp == into)
362: strcpy(into, "/"), dp = into + 1;
363: } else {
364: if (into[strlen(into) - 1] != '/')
365: (void) strcat(into, "/");
366: (void) strcat(into, file);
367: dp += strlen(file); /* stay at the end */
368: }
369: file = sp + 1;
370: } while (sp != 0);
371: }
372:
373: #endif CHDIR
374:
375: get_hdir(user, buf)
376: register char *user,
377: *buf;
378: {
379: char fbuf[LBSIZE],
380: pattern[100];
381: register int u_len;
382: File *fp;
383:
384: u_len = strlen(user);
385: fp = open_file("/etc/passwd", fbuf, F_READ, COMPLAIN, QUIET);
386: sprintf(pattern, "%s:[^:]*:[^:]*:[^:]*:[^:]*:\\([^:]*\\):", user);
387: while (f_gets(fp, genbuf, LBSIZE) != EOF)
388: if ((strncmp(genbuf, user, u_len) == 0) &&
389: (LookingAt(pattern, genbuf, 0))) {
390: putmatch(1, buf, FILESIZE);
391: close_file(fp);
392: return;
393: }
394: f_close(fp);
395: complain("[unknown user: %s]", user);
396: }
397:
398: PathParse(name, intobuf)
399: char *name,
400: *intobuf;
401: {
402: char localbuf[FILESIZE];
403:
404: intobuf[0] = localbuf[0] = '\0';
405: if (*name == '\0')
406: return;
407: if (*name == '~') {
408: if (name[1] == '/' || name[1] == '\0') {
409: strcpy(localbuf, HomeDir);
410: name++;
411: } else {
412: char *uendp = index(name, '/'),
413: unamebuf[30];
414:
415: if (uendp == 0)
416: uendp = name + strlen(name);
417: name = name + 1;
418: null_ncpy(unamebuf, name, uendp - name);
419: get_hdir(unamebuf, localbuf);
420: name = uendp;
421: }
422: } else if (*name == '\\')
423: name++;
424: (void) strcat(localbuf, name);
425: #ifdef CHDIR
426: dfollow(localbuf, intobuf);
427: #else
428: strcpy(intobuf, localbuf);
429: #endif
430: }
431:
432: filemunge(newname)
433: char *newname;
434: {
435: struct stat stbuf;
436:
437: if (newname == 0)
438: return;
439: if (stat(newname, &stbuf))
440: return;
441: if ((stbuf.st_ino != curbuf->b_ino) &&
442: ((stbuf.st_mode & S_IFMT) != S_IFCHR) &&
443: (strcmp(newname, curbuf->b_fname) != 0)) {
444: rbell();
445: confirm("\"%s\" already exists; overwrite it? ", newname);
446: }
447: }
448:
449: WrtReg()
450: {
451: DoWriteReg(0);
452: }
453:
454: AppReg()
455: {
456: DoWriteReg(1);
457: }
458:
459: int CreatMode = DFLT_MODE;
460:
461: DoWriteReg(app)
462: {
463: char fnamebuf[FILESIZE],
464: *fname;
465: Mark *mp = CurMark();
466: File *fp;
467:
468: /* Won't get here if there isn't a Mark */
469: fname = ask_file((char *) 0, fnamebuf);
470:
471: #ifdef BACKUPFILES
472: if (!app) {
473: filemunge(fname);
474:
475: if (BkupOnWrite)
476: file_backup(fname);
477: }
478: #else
479: if (!app)
480: filemunge(fname);
481: #endif
482:
483: fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, COMPLAIN, !QUIET);
484: putreg(fp, mp->m_line, mp->m_char, curline, curchar, YES);
485: close_file(fp);
486: }
487:
488: int OkayBadChars = 0;
489:
490: WriteFile()
491: {
492: char *fname,
493: fnamebuf[FILESIZE];
494:
495: fname = ask_file(curbuf->b_fname, fnamebuf);
496: /* Don't allow bad characters when creating new files. */
497: if (!OkayBadChars && strcmp(curbuf->b_fname, fnamebuf) != 0) {
498: static char *badchars = "!$^&*()~`{}\"'\\|<>? ";
499: register char *cp = fnamebuf;
500: register int c;
501:
502: while (c = *cp++)
503: if (c < ' ' || c == '\177' || index(badchars, c))
504: complain("'%p': bad character in filename.", c);
505: }
506:
507: chk_mtime(fname, "write");
508: filemunge(fname);
509: if (curbuf->b_type != B_IPROCESS)
510: curbuf->b_type = B_FILE; /* In case it wasn't before. */
511: setfname(curbuf, fname);
512: file_write(fname, 0);
513: unmodify();
514: }
515:
516: File *
517: open_file(fname, buf, how, ifbad, loudness)
518: register char *fname;
519: char *buf;
520: register int how;
521: {
522: register File *fp;
523:
524: io_chars = 0;
525: io_lines = 0;
526: tellall = loudness;
527:
528: fp = f_open(fname, how, buf, LBSIZE);
529: if (fp == NIL) {
530: message(IOerr((how == F_READ) ? "open" : "create", fname));
531: if (ifbad == COMPLAIN)
532: complain((char *) 0);
533: } else {
534: int readonly = FALSE;
535:
536: if (access(fname, W_OK) == -1 && errno != ENOENT)
537: readonly = TRUE;
538:
539: if (loudness != QUIET)
540: f_mess("\"%s\"%s", pr_name(fname),
541: readonly ? " [Read only]" : NullStr);
542: }
543: return fp;
544: }
545:
546: /* Check to see if the file has been modified since it was
547: last written. If so, make sure they know what they're
548: doing.
549:
550: I hate to use another stat(), but to use confirm we gotta
551: do this before we open the file. */
552:
553: chk_mtime(fname, how)
554: char *fname,
555: *how;
556: {
557: struct stat stbuf;
558: Buffer *b;
559: char *mesg = "Shall I go ahead and %s anyway? ";
560:
561: if ((curbuf->b_mtime != 0) && /* if we care ... */
562: (b = file_exists(fname)) && /* we already have this file */
563: (b == curbuf) && /* and it's the current buffer */
564: (stat(fname, &stbuf) != -1) && /* and we can stat it */
565: (stbuf.st_mtime != b->b_mtime)) { /* and there's trouble. */
566: rbell();
567: redisplay(); /* Ring that bell! */
568: TOstart("Warning", TRUE);
569: Typeout("\"%s\" now saved on disk is not what you last", pr_name(fname));
570: Typeout("visited or saved. Probably someone else is editing");
571: Typeout("your file at the same time. Type \"y\" if I should");
572: Typeout("%s anyway.", how);
573: f_mess(mesg, how);
574: TOstop();
575: confirm(mesg, how);
576: }
577: }
578:
579: file_write(fname, app)
580: char *fname;
581: {
582: File *fp;
583:
584: #ifdef BACKUPFILES
585: if (!app && BkupOnWrite)
586: file_backup(fname);
587: #endif
588:
589: fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, COMPLAIN, !QUIET);
590:
591: if (EndWNewline) { /* Make sure file ends with a newLine */
592: Bufpos save;
593:
594: DOTsave(&save);
595: ToLast();
596: if (length(curline)) /* Not a blank Line */
597: DoTimes(LineInsert(), 1); /* Make it blank */
598: SetDot(&save);
599: }
600: putreg(fp, curbuf->b_first, 0, curbuf->b_last, length(curbuf->b_last), NO);
601: set_ino(curbuf);
602: close_file(fp);
603: }
604:
605: ReadFile()
606: {
607: char *fname,
608: fnamebuf[FILESIZE];
609:
610: fname = ask_file(curbuf->b_fname, fnamebuf);
611: chk_mtime(fname, "read");
612:
613: if (IsModified(curbuf)) {
614: char *y_or_n;
615: int c;
616:
617: for (;;) {
618: rbell();
619: y_or_n = ask(NullStr, "Shall I make your changes to \"%s\" permanent? ", curbuf->b_name);
620: c = Upper(*y_or_n);
621: if (c == 'Y' || c == 'N')
622: break;
623: }
624: if (c == 'Y')
625: SaveFile();
626: }
627:
628: unmodify();
629: initlist(curbuf);
630: setfname(curbuf, fname);
631: read_file(fname, 0);
632: }
633:
634: InsFile()
635: {
636: char *fname,
637: fnamebuf[FILESIZE];
638:
639: fname = ask_file(curbuf->b_fname, fnamebuf);
640: read_file(fname, 1);
641: }
642:
643: #include "temp.h"
644:
645: int DOLsave = 0; /* Do Lsave flag. If lines aren't being save
646: when you think they should have been, this
647: flag is probably not being set, or is being
648: cleared before lsave() was called. */
649:
650: int nleft, /* Number of good characters left in current block */
651: tmpfd;
652: disk_line tline; /* Pointer to end of tmp file */
653:
654: char *tfname;
655:
656: tmpinit()
657: {
658: tfname = mktemp(TMPFILE);
659: (void) close(creat(tfname, 0600));
660: tmpfd = open(tfname, 2);
661: if (tmpfd == -1) {
662: printf("%s?\n", tfname);
663: finish(0);
664: }
665: block_init();
666: tline = 2;
667: }
668:
669: tmpclose()
670: {
671: (void) close(tmpfd);
672: tmpfd = -1;
673: (void) unlink(tfname);
674: }
675:
676: /* Get a line at `tl' in the tmp file into `buf' which should be LBSIZE
677: long. */
678:
679: int Jr_Len; /* Length of Just Read Line. */
680:
681: char *
682: getline(tl, buf)
683: disk_line tl;
684: char *buf;
685: {
686: register char *bp,
687: *lp;
688: register int nl;
689:
690: lp = buf;
691: bp = getblock(tl, READ);
692: nl = nleft;
693: tl &= ~OFFMSK;
694:
695: while (*lp++ = *bp++) {
696: if (--nl == 0) {
697: /* += INCRMT moves tl to the next block in
698: the tmp file. */
699: bp = getblock(tl += INCRMT, READ);
700: nl = nleft;
701: }
702: }
703: Jr_Len = (lp - buf) - 1;
704:
705: return buf;
706: }
707:
708: /* Put `buf' and return the disk address */
709:
710: int nretries = 0;
711:
712: disk_line
713: putline(buf)
714: char *buf;
715: {
716: register char *bp,
717: *lp;
718: register int nl;
719: disk_line tl;
720:
721: lp = buf;
722: tl = tline;
723: bp = getblock(tl, WRITE);
724: nl = nleft;
725: tl &= ~OFFMSK;
726: while (*bp = *lp++) {
727: if (*bp++ == '\n') {
728: *--bp = 0;
729: break;
730: }
731: if (--nl == 0) {
732: tline = (tl += INCRMT);
733: bp = getblock(tl, WRITE);
734: lp = buf; /* start over ... */
735: nretries++;
736: nl = nleft;
737: }
738: }
739: tl = tline;
740: tline += (((lp - buf) + BNDRY - 1) >> SHFT) & 077776;
741:
742: return tl;
743: }
744:
745: typedef struct block {
746: short b_dirty,
747: b_bno;
748: char b_buf[BUFSIZ];
749: struct block
750: *b_LRUnext,
751: *b_LRUprev,
752: *b_HASHnext;
753: } Block;
754:
755: #define HASHSIZE 7 /* Primes work best (so I'm told) */
756: #define B_HASH(bno) (bno % HASHSIZE)
757:
758: private Block b_cache[NBUF],
759: *bht[HASHSIZE] = {0}, /* Block hash table */
760: *f_block = 0,
761: *l_block = 0;
762: private int max_bno = -1,
763: NBlocks;
764:
765: private
766: block_init()
767: {
768: register Block *bp, /* Block pointer */
769: **hp; /* Hash pointer */
770: register short bno;
771:
772: for (bp = b_cache, bno = NBUF; --bno >= 0; bp++) {
773: NBlocks++;
774: bp->b_dirty = 0;
775: bp->b_bno = bno;
776: if (l_block == 0)
777: l_block = bp;
778: bp->b_LRUprev = 0;
779: bp->b_LRUnext = f_block;
780: if (f_block != 0)
781: f_block->b_LRUprev = bp;
782: f_block = bp;
783:
784: bp->b_HASHnext = *(hp = &bht[B_HASH(bno)]);
785: *hp = bp;
786: }
787: }
788:
789: private Block *
790: lookup(bno)
791: register short bno;
792: {
793: register Block *bp;
794:
795: for (bp = bht[B_HASH(bno)]; bp != 0; bp = bp->b_HASHnext)
796: if (bp->b_bno == bno)
797: break;
798: return bp;
799: }
800:
801: private
802: LRUunlink(b)
803: register Block *b;
804: {
805: if (b->b_LRUprev == 0)
806: f_block = b->b_LRUnext;
807: else
808: b->b_LRUprev->b_LRUnext = b->b_LRUnext;
809: if (b->b_LRUnext == 0)
810: l_block = b->b_LRUprev;
811: else
812: b->b_LRUnext->b_LRUprev = b->b_LRUprev;
813: }
814:
815: private Block *
816: b_unlink(bp)
817: register Block *bp;
818: {
819: register Block *hp,
820: *prev = 0;
821:
822: LRUunlink(bp);
823: /* Now that we have the block, we remove it from its position
824: in the hash table, so we can THEN put it somewhere else with
825: it's new block assignment. */
826:
827: for (hp = bht[B_HASH(bp->b_bno)]; hp != 0; prev = hp, hp = hp->b_HASHnext)
828: if (hp == bp)
829: break;
830: if (hp == 0) {
831: printf("\rBlock %d missing!", bp->b_bno);
832: finish(0);
833: }
834: if (prev)
835: prev->b_HASHnext = hp->b_HASHnext;
836: else
837: bht[B_HASH(bp->b_bno)] = hp->b_HASHnext;
838:
839: if (bp->b_dirty) { /* Do, now, the delayed write */
840: blkio(bp, write);
841: bp->b_dirty = 0;
842: }
843:
844: return bp;
845: }
846:
847: /* Get a block which contains at least part of the line with the address
848: atl. Returns a pointer to the block and sets the global variable
849: nleft (number of good characters left in the buffer). */
850:
851: char *
852: getblock(atl, iof)
853: disk_line atl;
854: {
855: register int bno,
856: off;
857: register Block *bp;
858: static Block *lastb = 0;
859:
860: bno = (atl >> OFFBTS) & BLKMSK;
861: off = (atl << SHFT) & LBTMSK;
862: if (bno >= NMBLKS)
863: error("Tmp file too large. Get help!");
864: nleft = BUFSIZ - off;
865: if (lastb != 0 && lastb->b_bno == bno)
866: return lastb->b_buf + off;
867:
868: /* The requested block already lives in memory, so we move
869: it to the end of the LRU list (making it Most Recently Used)
870: and then return a pointer to it. */
871:
872: if (bp = lookup(bno)) {
873: if (bp != l_block) {
874: LRUunlink(bp);
875: if (l_block == 0)
876: f_block = l_block = bp;
877: else
878: l_block->b_LRUnext = bp;
879: bp->b_LRUprev = l_block;
880: l_block = bp;
881: bp->b_LRUnext = 0;
882: }
883: if (bp->b_bno > max_bno)
884: max_bno = bp->b_bno;
885: bp->b_dirty |= iof;
886: lastb = bp;
887: return bp->b_buf + off;
888: }
889:
890: /* The block we want doesn't reside in memory so we take the
891: least recently used clean block (if there is one) and use
892: it. */
893:
894: bp = f_block;
895: if (bp->b_dirty) /* The best block is dirty ... */
896: SyncTmp();
897:
898: bp = b_unlink(bp);
899: if (l_block == 0)
900: l_block = f_block = bp;
901: else
902: l_block->b_LRUnext = bp; /* Place it at the end ... */
903: bp->b_LRUprev = l_block;
904: l_block = bp;
905: bp->b_LRUnext = 0; /* so it's Most Recently Used */
906:
907: bp->b_dirty = iof;
908: bp->b_bno = bno;
909: bp->b_HASHnext = bht[B_HASH(bno)];
910: bht[B_HASH(bno)] = bp;
911:
912: /* Get the current contents of the block UNLESS this is a new
913: block that's never been looked at before, i.e., it's past
914: the end of the tmp file. */
915:
916: if (bp->b_bno <= max_bno)
917: blkio(bp, read);
918: else
919: max_bno = bno;
920:
921: lastb = bp;
922: return bp->b_buf + off;
923: }
924:
925: char *
926: lbptr(line)
927: Line *line;
928: {
929: return getblock(line->l_dline, READ);
930: }
931:
932: private
933: blkio(b, iofcn)
934: register Block *b;
935: register int (*iofcn)();
936: {
937: (void) lseek(tmpfd, (long) ((unsigned) b->b_bno) * BUFSIZ, 0);
938: if ((*iofcn)(tmpfd, b->b_buf, BUFSIZ) != BUFSIZ)
939: error("Tmp file %s error.", (iofcn == read) ? "read" : "write");
940: }
941:
942: SyncTmp()
943: {
944: register Block *b;
945:
946: for (b = f_block; b != 0; b = b->b_LRUnext)
947: if (b->b_dirty) {
948: blkio(b, write);
949: b->b_dirty = 0;
950: }
951: }
952:
953: /* save the current contents of linebuf, if it has changed */
954:
955: lsave()
956: {
957: if (curbuf == 0 || !DOLsave) /* Nothing modified recently */
958: return;
959:
960: if (strcmp(lbptr(curline), linebuf) != 0)
961: SavLine(curline, linebuf); /* Put linebuf on the disk. */
962: DOLsave = 0;
963: }
964:
965: #ifdef BACKUPFILES
966: file_backup(fname)
967: char *fname;
968: {
969: char *s;
970: register int i;
971: int fd1,
972: fd2;
973: char tmp1[BUFSIZ],
974: tmp2[BUFSIZ];
975:
976: strcpy(tmp1, fname);
977:
978: if ((s = rindex(tmp1, '/')) == NULL)
979: sprintf(tmp2, "#%s", fname);
980: else {
981: *s++ = NULL;
982: sprintf(tmp2, "%s/#%s", tmp1, s);
983: }
984:
985: if ((fd1 = open(fname, 0)) < 0)
986: return;
987:
988: if ((fd2 = creat(tmp2, CreatMode)) < 0) {
989: (void) close(fd1);
990: return;
991: }
992:
993: while ((i = read(fd1, tmp1, sizeof(tmp1))) > 0)
994: write(fd2, tmp1, i);
995:
996: #ifdef BSD4_2
997: (void) fsync(fd2);
998: #endif
999: (void) close(fd2);
1000: (void) close(fd1);
1001: }
1002: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.