This is io.c in view mode; [Download] [Up]
/*************************************************************************** * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE * * is provided to you without charge, and with no warranty. You may give * * away copies of JOVE, including sources, provided that this notice is * * included in all the files. * ***************************************************************************/ #include "jove.h" #include "list.h" #include "fp.h" #include "termcap.h" #include "ctype.h" #include "disp.h" #include "scandir.h" #ifdef IPROCS # include <signal.h> #endif #ifdef MAC # include "mac.h" #else # include <sys/stat.h> #endif #ifdef UNIX # include <sys/file.h> #endif #ifdef MSDOS # include <fcntl.h> # include <io.h> # include <direct.h> # include <dos.h> #endif /* MSDOS */ #include <errno.h> private struct block *b_unlink proto((struct block *)), *lookup proto((int/*short*/)); private char *dbackup proto((char *, char *, int)), #if defined(MSDOS) *fixpath proto((char *)), #endif *getblock proto((daddr, int)); private void #if defined(MSDOS) abspath proto((char *, char *)), #endif fake_blkio proto((struct block *, int (*)())), DoWriteReg proto((int app)), LRUunlink proto((struct block *)), file_backup proto((char *fname)), real_blkio proto((struct block *, int (*)())), dfollow proto((char *, char *)); #if defined(MSDOS) private int Dchdir proto((char *)); #endif #ifndef W_OK # define W_OK 2 # define F_OK 0 #endif #define READ 0 #define WRITE 1 /* block operation read or write */ long io_chars; /* number of chars in this open_file */ int io_lines; /* number of lines in this open_file */ #if defined(VMUNIX) || defined(MSDOS) char iobuff[LBSIZE], genbuf[LBSIZE], linebuf[LBSIZE]; #else char *iobuff, *genbuf, *linebuf; #endif #ifdef BACKUPFILES int BkupOnWrite = 0; #endif void close_file(fp) File *fp; { if (fp) { if (fp->f_flags & F_TELLALL) add_mess(" %d lines, %D characters.", io_lines, io_chars); f_close(fp); } } /* Write the region from line1/char1 to line2/char2 to FP. This never CLOSES the file since we don't know if we want to. */ int EndWNewline = 1; void putreg(fp, line1, char1, line2, char2, makesure) register File *fp; Line *line1, *line2; int char1, char2, makesure; { register int c; register char *lp; if (makesure) (void) fixorder(&line1, &char1, &line2, &char2); while (line1 != line2->l_next) { lp = lcontents(line1) + char1; if (line1 == line2) { fputnchar(lp, (char2 - char1), fp); io_chars += (char2 - char1); } else { while ((c = *lp++) != '\0') { jputc(c, fp); io_chars += 1; } } if (line1 != line2) { io_lines += 1; io_chars += 1; #ifdef MSDOS jputc('\r', fp); #endif /* MSDOS */ jputc('\n', fp); } line1 = line1->l_next; char1 = 0; } flush(fp); } private void dofread(fp) register File *fp; { char end[LBSIZE]; int xeof = 0; Line *savel = curline; int savec = curchar; strcpy(end, linebuf + curchar); xeof = f_gets(fp, linebuf + curchar, (size_t) (LBSIZE - curchar)); SavLine(curline, linebuf); if (!xeof) do { curline = listput(curbuf, curline); xeof = f_getputl(curline, fp); } while (!xeof); getDOT(); linecopy(linebuf, (curchar = strlen(linebuf)), end); SavLine(curline, linebuf); IFixMarks(savel, savec, curline, curchar); } void read_file(file, is_insert) char *file; int is_insert; { Bufpos save; File *fp; if (is_insert == NO) curbuf->b_ntbf = NO; fp = open_file(file, iobuff, F_READ, NO, NO); if (fp == NIL) { if (!is_insert && errno == ENOENT) s_mess("(new file)"); else s_mess(IOerr("open", file)); return; } if (is_insert == NO) { set_ino(curbuf); if (fp->f_flags & F_READONLY) { set_arg_value(1); } else { set_arg_value(0); } TogMinor(ReadOnly); } DOTsave(&save); dofread(fp); if (is_insert && io_chars > 0) { modify(); set_mark(); } SetDot(&save); getDOT(); close_file(fp); } void SaveFile() { if (IsModified(curbuf)) { if (curbuf->b_fname == 0) WriteFile(); else { filemunge(curbuf->b_fname); #if !defined(MAC) && !defined(MSDOS) chk_mtime(curbuf, curbuf->b_fname, "save"); #endif file_write(curbuf->b_fname, 0); } } else message("No changes need to be written."); } char *HomeDir; /* home directory */ size_t HomeLen; /* length of home directory string */ private List *DirStack = 0; #define dir_name(dp) ((char *) list_data((dp))) #define PWD_PTR (list_data(DirStack)) #define PWD ((char *) PWD_PTR) char * pwd() { return (char *) PWD_PTR; } char * pr_name(fname, okay_home) char *fname; int okay_home; { int n; if (fname == 0) return 0; n = numcomp(fname, PWD); if ((PWD[n] == 0) && /* Matched to end of PWD */ (fname[n] == '/')) return fname + n + 1; if (okay_home && strcmp(HomeDir, "/") != 0 && strncmp(fname, HomeDir, HomeLen) == 0 && fname[HomeLen] == '/') { static char name_buf[100]; swritef(name_buf, "~%s", fname + HomeLen); return name_buf; } return fname; /* return entire path name */ } void Chdir() { char dirbuf[FILESIZE]; #ifdef MSDOS fmask = 0x10; #endif (void) ask_file((char *) 0, PWD, dirbuf); #ifdef MSDOS fmask = 0x13; if (Dchdir(dirbuf) == -1) #else if (chdir(dirbuf) == -1) #endif { s_mess("cd: cannot change into %s.", dirbuf); return; } UpdModLine = YES; setCWD(dirbuf); prCWD(); #ifdef MAC Bufchange++; #endif } #if defined(UNIX) # if !defined(BSD4_2) char * getwd(buffer) char *buffer; { Buffer *old = curbuf; char *ret_val; SetBuf(do_select((Window *) 0, "pwd-output")); curbuf->b_type = B_PROCESS; (void) UnixToBuf("pwd-output", NO, 0, YES, "/bin/pwd", (char *) 0); ToFirst(); strcpy(buffer, linebuf); SetBuf(old); return buffer; } # endif /* not BSD4_2 */ /* Check if dn is the name of the current working directory and that it is in cannonical form */ int chkCWD(dn) char *dn; { char filebuf[FILESIZE]; struct stat dnstat, dotstat; if (dn[0] != '/') return FALSE; /* need absolute pathname */ PathParse(dn, filebuf); return stat(filebuf, &dnstat) == 0 && stat(".", &dotstat) == 0 && dnstat.st_dev == dotstat.st_dev && dnstat.st_ino == dotstat.st_ino; } #endif /* UNIX */ void setCWD(d) char *d; { if (DirStack == NIL) list_push(&DirStack, (Element *) 0); if (PWD == 0) PWD_PTR = (Element *) emalloc((size_t) (strlen(d) + 1)); else PWD_PTR = (Element *) ralloc(PWD, strlen(d) + 1); strcpy(PWD, d); } void getCWD() { char *cwd; char pathname[FILESIZE]; #if defined(UNIX) && defined(JOB_CONTROL) extern char *getwd(); #endif #if defined(MSDOS) extern char *getcwd(); #endif #ifndef MSDOS cwd = getenv("CWD"); if (cwd == 0 || !chkCWD(cwd)) { cwd = getenv("PWD"); if (cwd == 0 || !chkCWD(cwd)) cwd = getwd(pathname); } #else /* MSDOS */ cwd = fixpath(getcwd(pathname, FILESIZE)); #endif /* MSDOS */ setCWD(cwd); } void prDIRS() { register List *lp; s_mess(": %f "); for (lp = DirStack; lp != NIL; lp = list_next(lp)) add_mess("%s ", pr_name(dir_name(lp), YES)); } void prCWD() { s_mess(": %f => \"%s\"", PWD); } void Pushd() { char *newdir, dirbuf[FILESIZE]; #ifdef MSDOS fmask = 0x10; #endif newdir = ask_file((char *) 0, NullStr, dirbuf); #ifdef MSDOS fmask = 0x13; #endif UpdModLine = YES; if (*newdir == 0) { /* Wants to swap top two entries */ char *old_top; if (list_next(DirStack) == NIL) complain("pushd: no other directory."); old_top = PWD; list_data(DirStack) = (Element *) dir_name(list_next(DirStack)); list_data(list_next(DirStack)) = (Element *) old_top; #ifdef MSDOS (void) Dchdir(PWD); #else (void) chdir(PWD); #endif } else { #ifdef MSDOS if (Dchdir(dirbuf) == -1) #else if (chdir(dirbuf) == -1) #endif { s_mess("pushd: cannot change into %s.", dirbuf); return; } (void) list_push(&DirStack, (Element *) 0); setCWD(dirbuf); } prDIRS(); } void Popd() { if (list_next(DirStack) == NIL) complain("popd: directory stack is empty."); UpdModLine = YES; free((char *) list_pop(&DirStack)); #ifdef MSDOS (void) Dchdir(PWD); /* If this doesn't work, we's in deep shit. */ #else (void) chdir(PWD); /* If this doesn't work, we's in deep shit. */ #endif prDIRS(); } private char * dbackup(base, offset, c) register char *base, *offset; register int c; { while (offset > base && *--offset != c) ; return offset; } private void dfollow(file, into) char *file, *into; { char *dp, #ifdef MSDOS filefix[FILESIZE], #endif *sp; #ifndef MSDOS if (*file == '/') { /* Absolute pathname */ strcpy(into, "/"); file += 1; } else strcpy(into, PWD); #else abspath(file, filefix); /* convert to absolute pathname */ strcpy(into, filefix); /* and forget about drives */ into[3] = 0; into = &(into[2]); file = &(filefix[3]); #endif dp = into + strlen(into); sp = file; do { if (*file == 0) break; if ((sp = strchr(file, '/')) != '\0') *sp = 0; if (strcmp(file, ".") == 0) ; /* So it will get to the end of the loop */ else if (strcmp(file, "..") == 0) { *(dp = dbackup(into, dp, '/')) = 0; if (dp == into) strcpy(into, "/"), dp = into + 1; } else { if (into[strlen(into) - 1] != '/') (void) strcat(into, "/"), dp += 1; (void) strcat(into, file); dp += strlen(file); /* stay at the end */ } file = sp + 1; } while (sp != 0); } #if defined(UNIX) # if defined(YP_PASSWD) #include <pwd.h> private void get_hdir(user, buf) register char *user, *buf; { struct passwd *p; p = getpwnam(user); endpwent(); if (p == NULL) { add_mess(" [unknown user: %s]", user); SitFor(7); complain((char *) 0); /* NOTREACHED */ } strcpy(buf, p->pw_dir); } #else private get_hdir(user, buf) register char *user, *buf; { char fbuf[LBSIZE], pattern[100]; register int u_len; File *fp; u_len = strlen(user); fp = open_file("/etc/passwd", fbuf, F_READ, YES, YES); swritef(pattern, "%s:[^:]*:[^:]*:[^:]*:[^:]*:\\([^:]*\\):", user); while (f_gets(fp, genbuf, LBSIZE) != EOF) if ((strncmp(genbuf, user, u_len) == 0) && (LookingAt(pattern, genbuf, 0))) { putmatch(1, buf, FILESIZE); close_file(fp); return; } close_file(fp); add_mess(" [unknown user: %s]", user); SitFor(7); complain((char *) 0); } #endif /* YP_PASSWD */ #endif /* UNIX */ void PathParse(name, intobuf) char *name, *intobuf; { char localbuf[FILESIZE]; intobuf[0] = localbuf[0] = '\0'; if (*name == '\0') return; if (*name == '~') { if (name[1] == '/' || name[1] == '\0') { strcpy(localbuf, HomeDir); name += 1; } #if !(defined(MSDOS) || defined(MAC)) /* may add for mac in future */ else { char *uendp = strchr(name, '/'), unamebuf[30]; if (uendp == 0) uendp = name + strlen(name); name += 1; null_ncpy(unamebuf, name, (size_t) (uendp - name)); get_hdir(unamebuf, localbuf); name = uendp; } #endif } #ifndef MSDOS else if (*name == '\\') name += 1; #endif /* MSDOS */ (void) strcat(localbuf, name); dfollow(localbuf, intobuf); } void filemunge(newname) char *newname; { struct stat stbuf; if (newname == 0) return; if (stat(newname, &stbuf)) return; #ifndef MSDOS if (((stbuf.st_dev != curbuf->b_dev) || (stbuf.st_ino != curbuf->b_ino)) && #else /* MSDOS */ if ( /* (stbuf.st_ino != curbuf->b_ino) && */ #endif /* MSDOS */ #ifndef MAC ((stbuf.st_mode & S_IFMT) != S_IFCHR) && #endif (curbuf->b_fname==NIL || strcmp(newname, curbuf->b_fname) != 0)) { rbell(); confirm("\"%s\" already exists; overwrite it? ", newname); } } void WrtReg() { DoWriteReg(NO); } void AppReg() { DoWriteReg(YES); } int CreatMode = DFLT_MODE; private void DoWriteReg(app) int app; { char fnamebuf[FILESIZE], *fname; Mark *mp = CurMark(); File *fp; /* Won't get here if there isn't a Mark */ fname = ask_file((char *) 0, (char *) 0, fnamebuf); #ifdef BACKUPFILES if (app == NO) { filemunge(fname); if (BkupOnWrite) file_backup(fname); } #else if (!app) filemunge(fname); #endif fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, YES, NO); putreg(fp, mp->m_line, mp->m_char, curline, curchar, YES); close_file(fp); } int OkayBadChars = 0; void WriteFile() { char *fname, fnamebuf[FILESIZE]; #ifdef MAC if (Macmode) { if(!(fname = pfile(fnamebuf))) return; } else #endif /* MAC */ fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf); /* Don't allow bad characters when creating new files. */ if (!OkayBadChars && (curbuf->b_fname==NIL || strcmp(curbuf->b_fname, fnamebuf) != 0)) { #ifdef UNIX static char *badchars = "!$^&*()~`{}\"'\\|<>? "; #endif /* UNIX */ #ifdef MSDOS static char *badchars = "*|<>? "; #endif /* MSDOS */ #ifdef MAC static char *badchars = ":"; #endif /* MAC */ register char *cp = fnamebuf; register int c; while ((c = *cp++ & CHARMASK) != '\0') /* avoid sign extension... */ if (c < ' ' || c == '\177' || strchr(badchars, c)) complain("'%p': bad character in filename.", c); } #if !defined(MAC) && !defined(MSDOS) chk_mtime(curbuf, fname, "write"); #endif filemunge(fname); curbuf->b_type = B_FILE; /* in case it wasn't before */ setfname(curbuf, fname); file_write(fname, 0); } /* Open file FNAME supplying the buffer IO routine with buffer BUF. HOW is F_READ, F_WRITE or F_APPEND. IFBAD == COMPLAIN means that if we fail at opening the file, call complain. LOUDNESS says whether or not to print the "reading ..." message on the message line. NOTE: This opens the pr_name(fname, NO) of fname. That is, FNAME is usually an entire pathname, which can be slow when the pathname is long and there are lots of symbolic links along the way (which has become very common in my experience). So, this speeds up opens file names in the local directory. It will not speed up things like "../scm/foo.scm" simple because by the time we get here that's already been expanded to an absolute pathname. But this is a start. */ File * open_file(fname, buf, how, complainifbad, quiet) register char *fname; char *buf; register int how; int complainifbad, quiet; { register File *fp; io_chars = 0; io_lines = 0; fp = f_open(pr_name(fname, NO), how, buf, LBSIZE); if (fp == NIL) { message(IOerr((how == F_READ) ? "open" : "create", fname)); if (complainifbad) complain((char *) 0); } else { int rd_only = FALSE; #ifndef MAC if (access(pr_name(fname, NO), W_OK) == -1 && errno != ENOENT) { rd_only = TRUE; fp->f_flags |= F_READONLY; } #endif if (!quiet) { fp->f_flags |= F_TELLALL; f_mess("\"%s\"%s", pr_name(fname, YES), rd_only ? " [Read only]" : NullStr); } } return fp; } #ifndef MSDOS /* Check to see if the file has been modified since it was last written. If so, make sure they know what they're doing. I hate to use another stat(), but to use confirm we gotta do this before we open the file. NOTE: This stats FNAME after converting it to a path-relative name. I can't see why this would cause a problem ... */ void chk_mtime(thisbuf, fname, how) Buffer *thisbuf; char *fname, *how; { struct stat stbuf; Buffer *b; char *mesg = "Shall I go ahead and %s anyway? "; if ((thisbuf->b_mtime != 0) && /* if we care ... */ ((b = file_exists(fname)) != NIL) && /* we already have this file */ (b == thisbuf) && /* and it's the current buffer */ (stat(pr_name(fname, NO), &stbuf) != -1) && /* and we can stat it */ (stbuf.st_mtime != b->b_mtime)) { /* and there's trouble. */ rbell(); redisplay(); /* Ring that bell! */ TOstart("Warning", TRUE); Typeout("\"%s\" now saved on disk is not what you last", pr_name(fname, YES)); Typeout("visited or saved. Probably someone else is editing"); Typeout("your file at the same time."); if (how) { Typeout(""); Typeout("Type \"y\" if I should %s, anyway.", how); f_mess(mesg, how); } TOstop(); if (how) confirm(mesg, how); } } #endif /* MSDOS */ void file_write(fname, app) char *fname; int app; { File *fp; #ifdef BACKUPFILES if (!app && BkupOnWrite) file_backup(fname); #endif fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, YES, NO); if (EndWNewline) { /* Make sure file ends with a newLine */ Bufpos save; DOTsave(&save); ToLast(); if (length(curline)) /* Not a blank Line */ LineInsert(1); SetDot(&save); } putreg(fp, curbuf->b_first, 0, curbuf->b_last, length(curbuf->b_last), NO); close_file(fp); set_ino(curbuf); unmodify(); } void ReadFile() { Buffer *bp; char *fname, fnamebuf[FILESIZE]; int lineno; #ifdef MAC if(Macmode) { if(!(fname = gfile(fnamebuf))) return; } else #endif /* MAC */ fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf); #if !(defined(MSDOS) || defined(MAC)) chk_mtime(curbuf, fname, "read"); #endif /* MSDOS || MAC */ if (IsModified(curbuf)) { char *y_or_n; int c; for (;;) { rbell(); y_or_n = ask(NullStr, "Shall I make your changes to \"%s\" permanent? ", curbuf->b_name); c = CharUpcase(*y_or_n); if (c == 'Y' || c == 'N') break; } if (c == 'Y') SaveFile(); } if ((bp = file_exists(fnamebuf)) != NIL && (bp == curbuf)) lineno = pnt_line() - 1; else lineno = 0; unmodify(); initlist(curbuf); setfname(curbuf, fname); read_file(fname, 0); SetLine(next_line(curbuf->b_first, lineno)); } void InsFile() { char *fname, fnamebuf[FILESIZE]; #ifdef MAC if(Macmode) { if(!(fname = gfile(fnamebuf))) return; } else #endif /* MAC */ fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf); read_file(fname, 1); } #include "temp.h" int DOLsave = 0; /* Do Lsave flag. If lines aren't being saved when you think they should have been, this flag is probably not being set, or is being cleared before lsave() was called. */ private int nleft, /* number of good characters left in current block */ tmpfd = -1; daddr DFree = 1; /* pointer to end of tmp file */ private char *tfname; void tmpinit() { char buf[FILESIZE]; #ifdef MAC swritef(buf, "%s/%s", HomeDir, d_tempfile); #else swritef(buf, "%s/%s", TmpFilePath, d_tempfile); #endif tfname = copystr(buf); tfname = mktemp(tfname); (void) close(creat(tfname, 0600)); #ifndef MSDOS tmpfd = open(tfname, 2); #else /* MSDOS */ tmpfd = open(tfname, 0x8002); /* MSDOS fix */ #endif /* MSDOS */ if (tmpfd == -1) complain("Warning: cannot create tmp file!"); } void tmpclose() { if (tmpfd == -1) return; (void) close(tmpfd); tmpfd = -1; (void) unlink(tfname); } /* get a line at `tl' in the tmp file into `buf' which should be LBSIZE long */ int Jr_Len; /* length of Just Read Line */ #ifdef MAC /* The Lighspeed compiler can't copy with static here */ char *getblock(); #else private char *getblock(); #endif void getline(addr, buf) daddr addr; register char *buf; { register char *bp, *lp; lp = buf; bp = getblock(addr >> 1, READ); do ; while ((*lp++ = *bp++) != '\0'); Jr_Len = (lp - buf) - 1; } /* Put `buf' and return the disk address */ daddr putline(buf) char *buf; { register char *bp, *lp; register int nl; daddr free_ptr; lp = buf; free_ptr = DFree; bp = getblock(free_ptr, WRITE); nl = nleft; free_ptr = blk_round(free_ptr); while ((*bp = *lp++) != '\0') { if (*bp++ == '\n') { *--bp = 0; break; } if (--nl == 0) { free_ptr = forward_block(free_ptr); DFree = free_ptr; bp = getblock(free_ptr, WRITE); lp = buf; /* start over ... */ nl = nleft; } } free_ptr = DFree; DFree += (((lp - buf) + CH_SIZE - 1) / CH_SIZE); /* (lp - buf) includes the null */ return (free_ptr << 1); } /* The theory is that critical section of code inside this procedure will never cause a problem to occur. Basically, we need to ensure that two blocks are in memory at the same time, but I think that this can never screw up. */ #define lockblock(addr) #define unlockblock(addr) daddr f_getputl(line, fp) Line *line; register File *fp; { register char *bp; register int c, nl, room = LBSIZE; daddr free_ptr; char *base; #ifdef MSDOS char crleft = 0; #endif /* MSDOS */ free_ptr = DFree; base = bp = getblock(free_ptr, WRITE); nl = nleft; free_ptr = blk_round(free_ptr); while (--room > 0) { /* We can't store NUL in our buffer, so ignore it. * Of course, with a little ingenuity we could: * NUL could be represented by \n! */ do { #ifdef MSDOS if (crleft) { c = crleft; crleft = 0; } else #endif /* MSDOS */ c = jgetc(fp); } while (c == '\0'); if (c == EOF || c == '\n') break; #ifdef MSDOS if (c == '\r' && (crleft = jgetc(fp)) == '\n') { crleft = 0; break; } #endif /* MSDOS */ if (--nl == 0) { char *newbp; size_t nbytes; lockblock(free_ptr); DFree = free_ptr = forward_block(free_ptr); nbytes = bp - base; newbp = getblock(free_ptr, WRITE); nl = nleft; byte_copy(base, newbp, nbytes); bp = newbp + nbytes; base = newbp; unlockblock(free_ptr); } *bp++ = c; } *bp++ = '\0'; free_ptr = DFree; DFree += (((bp - base) + CH_SIZE - 1) / CH_SIZE); line->l_dline = (free_ptr << 1); if (room == 0) { add_mess(" [Line too long]"); rbell(); return EOF; } if (c == EOF) { if (--bp != base) add_mess(" [Incomplete last line]"); return EOF; } io_lines += 1; return 0; } typedef struct block { short b_dirty, b_bno; char b_buf[JBUFSIZ]; struct block *b_LRUnext, *b_LRUprev, *b_HASHnext; } Block; #define HASHSIZE 7 /* Primes work best (so I'm told) */ #define B_HASH(bno) ((bno) % HASHSIZE) #ifdef MAC private Block *b_cache, #else private Block b_cache[NBUF], #endif *bht[HASHSIZE], /* Block hash table. Must be zero initially */ *f_block = 0, *l_block = 0; private int max_bno = -1, NBlocks; #ifdef MAC void (*blkio)(); #else private void (*blkio) proto((Block *, int (*)())); #endif /* MAC */ #ifdef MAC make_cache() /* Only 32K of static space on Mac, so... */ { return((b_cache = (Block *) calloc(NBUF,sizeof(Block))) == 0 ? 0 : 1); } #endif /* MAC */ extern int read(), write(); private void real_blkio(b, iofcn) register Block *b; #if defined(MAC) || defined(IBMPC) register int (*iofcn)(); #else register int (*iofcn) proto((int, UnivPtr, size_t)); #endif /* MAC */ { (void) lseek(tmpfd, (long) ((unsigned) b->b_bno) * JBUFSIZ, 0); if ((*iofcn)(tmpfd, b->b_buf, (size_t)JBUFSIZ) != JBUFSIZ) error("[Tmp file %s error; to continue editing would be dangerous]", (iofcn == read) ? "READ" : "WRITE"); } private void fake_blkio(b, iofcn) register Block *b; register int (*iofcn)(); { tmpinit(); blkio = real_blkio; real_blkio(b, iofcn); } void d_cache_init() { register Block *bp, /* Block pointer */ **hp; /* Hash pointer */ register short bno; for (bp = b_cache, bno = NBUF; --bno >= 0; bp++) { NBlocks += 1; bp->b_dirty = 0; bp->b_bno = bno; if (l_block == 0) l_block = bp; bp->b_LRUprev = 0; bp->b_LRUnext = f_block; if (f_block != 0) f_block->b_LRUprev = bp; f_block = bp; bp->b_HASHnext = *(hp = &bht[B_HASH(bno)]); *hp = bp; } blkio = fake_blkio; } void SyncTmp() { register Block *b; #ifdef IBMPC register int bno = 0; /* sync the blocks in order, for file systems that don't allow holes (MSDOS). Perhaps this benefits floppy-based file systems. */ for (bno = 0; bno <= max_bno; ) { if ((b = lookup(bno++)) && b->b_dirty) { (*blkio)(b, write); b->b_dirty = 0; } } #else for (b = f_block; b != 0; b = b->b_LRUnext) if (b->b_dirty) { (*blkio)(b, write); b->b_dirty = 0; } #endif } private Block * lookup(bno) register short bno; { register Block *bp; for (bp = bht[B_HASH(bno)]; bp != 0; bp = bp->b_HASHnext) if (bp->b_bno == bno) break; return bp; } private void LRUunlink(b) register Block *b; { if (b->b_LRUprev == 0) f_block = b->b_LRUnext; else b->b_LRUprev->b_LRUnext = b->b_LRUnext; if (b->b_LRUnext == 0) l_block = b->b_LRUprev; else b->b_LRUnext->b_LRUprev = b->b_LRUprev; } private Block * b_unlink(bp) register Block *bp; { register Block *hp, *prev = 0; LRUunlink(bp); /* Now that we have the block, we remove it from its position in the hash table, so we can THEN put it somewhere else with it's new block assignment. */ for (hp = bht[B_HASH(bp->b_bno)]; hp != 0; prev = hp, hp = hp->b_HASHnext) if (hp == bp) break; if (hp == 0) { writef("\rBlock %d missing!", bp->b_bno); finish(0); } if (prev) prev->b_HASHnext = hp->b_HASHnext; else bht[B_HASH(bp->b_bno)] = hp->b_HASHnext; if (bp->b_dirty) { /* do, now, the delayed write */ (*blkio)(bp, write); bp->b_dirty = 0; } return bp; } /* Get a block which contains at least part of the line with the address atl. Returns a pointer to the block and sets the global variable nleft (number of good characters left in the buffer). */ private char * getblock(atl, iof) daddr atl; int iof; { register int bno, off; register Block *bp; static Block *lastb = 0; bno = da_to_bno(atl); off = da_to_off(atl); if (da_too_huge(atl)) error("Tmp file too large. Get help!"); nleft = JBUFSIZ - off; if (lastb != 0 && lastb->b_bno == bno) { lastb->b_dirty |= iof; return lastb->b_buf + off; } /* The requested block already lives in memory, so we move it to the end of the LRU list (making it Most Recently Used) and then return a pointer to it. */ if ((bp = lookup(bno)) != NIL) { if (bp != l_block) { LRUunlink(bp); if (l_block == 0) f_block = l_block = bp; else l_block->b_LRUnext = bp; bp->b_LRUprev = l_block; l_block = bp; bp->b_LRUnext = 0; } if (bp->b_bno > max_bno) max_bno = bp->b_bno; bp->b_dirty |= iof; lastb = bp; return bp->b_buf + off; } /* The block we want doesn't reside in memory so we take the least recently used clean block (if there is one) and use it. */ bp = f_block; if (bp->b_dirty) /* The best block is dirty ... */ SyncTmp(); bp = b_unlink(bp); if (l_block == 0) l_block = f_block = bp; else l_block->b_LRUnext = bp; /* Place it at the end ... */ bp->b_LRUprev = l_block; l_block = bp; bp->b_LRUnext = 0; /* so it's Most Recently Used */ bp->b_dirty = iof; bp->b_bno = bno; bp->b_HASHnext = bht[B_HASH(bno)]; bht[B_HASH(bno)] = bp; /* Get the current contents of the block UNLESS this is a new block that's never been looked at before, i.e., it's past the end of the tmp file. */ if (bp->b_bno <= max_bno) (*blkio)(bp, read); else max_bno = bno; lastb = bp; return bp->b_buf + off; } char * lbptr(line) Line *line; { return getblock(line->l_dline >> 1, READ); } /* save the current contents of linebuf, if it has changed */ void lsave() { if (curbuf == 0 || !DOLsave) /* Nothing modified recently */ return; if (strcmp(lbptr(curline), linebuf) != 0) SavLine(curline, linebuf); /* Put linebuf on the disk. */ DOLsave = 0; } #ifdef BACKUPFILES private void file_backup(fname) char *fname; { #ifndef MSDOS char *s; register int i; int fd1, fd2; char tmp1[JBUFSIZ], tmp2[JBUFSIZ]; struct stat buf; int mode; strcpy(tmp1, fname); if ((s = strrchr(tmp1, '/')) == NULL) swritef(tmp2, "#%s~", fname); else { *s++ = '\0'; swritef(tmp2, "%s/#%s~", tmp1, s); } if ((fd1 = open(fname, 0)) < 0) return; /* create backup file with same mode as input file */ #ifndef MAC if (fstat(fd1, &buf) != 0) mode = CreatMode; else #endif mode = buf.st_mode; if ((fd2 = creat(tmp2, mode)) < 0) { (void) close(fd1); return; } while ((i = read(fd1, tmp1, sizeof(tmp1))) > 0) write(fd2, tmp1, (size_t) i); #ifdef BSD4_2 (void) fsync(fd2); #endif (void) close(fd2); (void) close(fd1); #else /* MSDOS */ char *dot, *slash, tmp[FILESIZE]; strcpy(tmp, fname); slash = basename(tmp); if (dot = strrchr(slash, '.')) { if (!stricmp(dot,".bak")) return; else *dot = 0; } strcat(tmp, ".bak"); unlink(tmp); rename(fname, tmp); #endif /* MSDOS */ } #endif #if defined(MSDOS) private int /* chdir + drive */ Dchdir(to) char *to; { unsigned d, dd, n; if (to[1] == ':') { d = to[0]; if (d >= 'a') d = d - 'a' + 1; if (d >= 'A') d = d - 'A' + 1; _dos_getdrive(&dd); if (dd != d) _dos_setdrive(d, &n); if (to[2] == 0) return 0; } return chdir(to); } private char * fixpath(p) char *p; { char *pp = p; while (*p) { if (*p == '\\') *p = '/'; p++; } return(strlwr(pp)); } private void abspath(so, dest) char *so, *dest; { char cwd[FILESIZE], cwdD[3], cwdDIR[FILESIZE], cwdF[9], cwdEXT[5], soD[3], soDIR[FILESIZE], soF[9], soEXT[5]; char *drive, *path; _splitpath(fixpath(so), soD, soDIR, soF, soEXT); getcwd(cwd, FILESIZE); if (*soD != 0) { Dchdir(soD); /* this is kinda messy */ getcwd(cwdDIR, FILESIZE); /* should probably just */ Dchdir(cwd); /* call DOS to do it */ strcpy(cwd, cwdDIR); } (void) fixpath(cwd); if (cwd[strlen(cwd)-1] != '/') strcat(cwd, "/x.x"); /* need dummy filename */ _splitpath(fixpath(cwd), cwdD, cwdDIR, cwdF, cwdEXT); drive = (*soD == 0) ? cwdD : soD; if (*soDIR != '/') path = strcat(cwdDIR, soDIR); else path = soDIR; _makepath(dest, drive, path, soF, soEXT); fixpath(dest); /* can't do it often enough */ } #endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.