#include "ded.h" #include "char.h" #include "file.h" #include "ter.h" /* Modified to allow production of backup (".old") files to be inhibited * PLS - UMIST, 15/2/82 * When editing a file with more than one link (strategy 'b'), a backup * file is still created in case of a write failure, but is deleted on * normal exit. Suffix of backup file changed to ".bak". * PLS - 24/8/82 */ /* #define BACKUP /* Define this to re-instate full backup feature */ /************************************************************************ * * * copyright Richard Bornat 1981 * * * ************************************************************************/ /* procedures to set up the input and output file systems */ int io_file; char io_buf[512]; int io_block; char *io_p, *io_start, *io_lim; /* open a file for reading - used in infile and in do_read */ void openinput(fname, crash) char *fname; int (*crash)(); { extern quit(); if ((io_file = open(fname, 0)) == -1) { if (errno == EACCES || crash != quit) (*crash)("cannot read file %s", fname); else quit("unix i/o error - errno %d [openinput]", errno); } io_p = io_start = io_buf; inblock(0); } /* close input file */ void closeinput() { close(io_file); } /* open file for appending */ openapp(fname) char *fname; { struct stat statbuf; if (stat(fname, &statbuf) == -1) /* can't find file */ return(createoutput(fname, 0666)); else if ((io_file = open(fname,2)) == -1) return(false); else { #ifdef V7 io_p = io_start = io_buf + (statbuf.st_size & 0777); lseek(io_file, (long) 0, 2); /* to the end of the file */ #else io_p = io_start = io_buf + (statbuf.size1 & 0777); seek(io_file, 0, 2); /* to the end of the file */ #endif return(true); } } /* close file after appending */ closeapp(fname, crash) char *fname; int (*crash)(); { closeoutput(fname, crash); } /* create an output file */ createoutput(fname, mode) char *fname; int mode; { struct stat statbuf; if (mode==-1) { if (stat(fname, &statbuf) == -1) mode = 0666; else #ifdef V7 mode = (statbuf.st_mode) & 07777; #else mode = (statbuf.flags) & 07777; #endif } if ((io_file = creat(fname,mode)) == -1) return (false); else { io_p = io_start = io_buf; return(true); } } /* and close the output file */ closeoutput(fname, crash) char *fname; int (*crash)(); { outblock(fname, crash); close(io_file); } /* procedure to save the entire contents of the edited file */ savefile(err, dlogging) int (*err)(); int dlogging; { register int diag1=false, diag2=false; struct stat filestat; register int f_mode=0666; char newname[ENOUGH], oldname[ENOUGH]; /* check whether file exists at all */ if (stat(filename, &filestat) != -1) { /* file exists - find its mode and whether linked or not */ #ifdef V7 f_mode = (filestat.st_mode) & 07777; if (filestat.st_nlink <= 1) #else f_mode = (filestat.flags) & 07777; if (filestat.nlinks <= 1) #endif { /* Fast strategy, usable when the file has no links. * First, write the new file in xxxx.nded, then * delete the .bak file, rename the source file .bak, * rename the new file as source file */ /* try to create a new version */ cat3(pathname,pidname,".nded",newname); if (!createoutput(newname, f_mode)) goto strat_b; writefile(newname); /* this must work */ #ifdef BACKUP /* delete the .bak file */ ncat2(filename,".bak",oldname); unlink(oldname); /* doesn't matter if this fails */ /* rename the source file, if possible */ if (link(filename, oldname) == -1) { unlink(newname); goto strat_b; } #endif if (unlink(filename) == -1) { unlink(newname); #ifdef BACKUP unlink(oldname); #endif goto strat_b; } /* rename the new file as source file */ if (link(newname, filename) == -1) { unlink(newname); #ifdef BACKUP unlink(oldname); #endif goto strat_b; } unlink(newname); /* doesn't really matter if this fails */ #ifdef BACKUP chmod(oldname, f_mode | 0600); /* nor this */ #endif goto all_done; /* OUCH */ } else { strat_b: /* come here when the file has links, or the * fast strategy won't work for any reason. * First re-write the .bak file, then re-write the source file */ { int oldf, filef; /* first make a copy of the existing file */ ncat2(filename, ".bak", oldname); if ((oldf = creat(oldname, f_mode | 0600)) == -1) { ncat2(tailname, ".bak", oldname); if ((oldf = creat(oldname, f_mode | 0600)) == -1) { cat3("/tmp/", pidname, ".bak", oldname); if ((oldf = creat(oldname, f_mode | 0600)) == -1) editerror("cannot write .bak file"); } diag1 = true; } if ((filef = open(filename, 0)) == -1) editerror("cannot re-open input file"); { int bcount; char f_buf[512]; while ((bcount = read(filef, f_buf, 512)) > 0) if (write(oldf, f_buf, bcount)!=bcount) editerror("write failed on .bak file - no space?"); } close(oldf); close(filef); } } } /* now write the file */ { char *filen = filename, newname[ENOUGH]; if (!createoutput(filen, f_mode)) { filen = newname; cat2(pidname, "dedout", newname); if (!createoutput(filen, f_mode)) { cat3("/tmp/", pidname, "dedout", newname); if (!createoutput(filen, f_mode)) editerror("cannot write output file"); } diag2 = true; } writefile(filen); #ifndef BACKUP unlink(oldname); /* delete backup file if write successful */ #endif #ifdef BACKUP if (diag1 & diag2) (*err)("old file is %s, new file is %s", oldname, filen); else if (diag1) (*err)("old file is %s", oldname); else #endif if (diag2) (*err)("edited file is %s", filen); } all_done: if (dlogging && NORMAL_INPUT) { dlogflush(); close(dlogger); if ((dlogger = creat_dlog(dlogname)) == -1) editerror("cannot re-create .dlog file"); } filewritten = true; } char *tabs(n, wbuf) int n; char *wbuf; { register int rn; register char *rw; rn = n; rw = wbuf; while (rn>=8) { *rw++ = c_TAB; rn -= 8; } while (rn>0) { *rw++ = c_SPACE; rn--; } return(rw); } /* write the data in the file */ writefile(fname) char *fname; { register int my_maxl = maxl, i; extern editerror(); /* find true file length */ while (my_maxl!=-1 && emptyline(my_maxl)) my_maxl--; for (i = 0; i!=my_maxl+1; i++) outline(i, fname, editerror); closeoutput(fname, editerror); tmp_changed = false; } /* write out one line */ outline(fline, fname, crash) int fline; char *fname; int (*crash)(); { char lbuf[ENOUGH], wbuf[ENOUGH+1]; register char c, *lp, *fp; char *fplim; fp = io_p; fplim = &io_buf[511]; getline(fline,lbuf); tranline(lbuf+MARGIN, wbuf, true); lp = wbuf; do { if (fp>fplim) { io_p = fp; outblock(fname, crash); fp = io_buf; } c = *fp++ = *lp++; } while (c != 0); fp--; /* back over the zero */ io_p = fp; } /* write out one block (or less) */ outblock(fname, crash) char *fname; int (*crash)(); { register nchars = io_p-io_start; if (nchars > 0) if (write(io_file, io_start, nchars) != nchars) (*crash)("?? write failed on %s - no space ??", fname); io_start = io_buf; /* on everything but the first block */ } /* translate from screen format to disk format */ tranline(lbuf, wbuf, lf_needed) char *lbuf, *wbuf; { register char *rl, *rw; register char c; char cb; rl = lbuf; rw = (tbout && *rl==c_SPACE ? 0 : wbuf); while (c = *rl++) if (c==c_CONTROL) { if (rw==0) rw = tabs(rl-lbuf-1, wbuf); c = *rl++; if (c=='?') *rw++ = 0177; else if ('@'<=c && c<='_') *rw++ = c-0100; else if ('a'<=c && c<='z') *rw++ = c-0140; else if (c==0) { *rw++ = '\0'; return; } /* broken line */ else rl--; /* bad conversion - forget it */ } else switch (ictab[c]) { case MODIFY: if (rw==0) rw = tabs(rl-lbuf-1, wbuf); /* convert back to {, } etc. */ c = *rl++; cb = (*ter.out_two)(c); if (cb!=c || cb==c_MODIFY) *rw++ = cb; else { /* bad conversion ! */ rl--; *rw++ = c_MODIFY; } break; case SPACE: if (rw != 0) *rw++ = c; break; default: if (rw==0) rw = tabs(rl-lbuf-1, wbuf); *rw++ = c; break; } if (rw==0) rw = wbuf; if (lf_needed) *rw++ = '\n'; *rw++ = '\0'; } /* read a single line from the file and convert it into a screen line */ int ded_inline(linebuf, crash) char *linebuf; int (*crash)(); { char *lastchar, *lastin, *eol; register char *lp; register char c; char ctype; register char *inp; char *lplim; char *lastspace, *inspace; lastchar=0; eol=linebuf; lp = linebuf; lplim = lp+RIGHTCOL-MARGIN; /* leave room for tag on line */ inp = io_p; lastspace = inspace = 0; while (true) { if (inp>=io_lim) { inblock(io_block+1); if (io_lim<=io_buf) { io_p = io_buf; *eol='\0'; return((int)lastchar); } else inp = io_buf; } c = *inp++; retry: /* see SPECIAL below */ ctype = ictab[c]; reswitch: /* see SPECIAL below */ switch (ctype) { case SPECIAL: if ((ctype = (*ter.special)(false, c))>=0) goto reswitch; else { c = -ctype; goto retry; } case SPACE: if (lp>lplim) break; else { if (lastchar!=0) { lastchar=lp; lastin=inp; } *lp++ = c; if (lp<=lplim) { lastspace=lp-1; inspace=inp; } continue; } case ONE: if (lp>lplim) break; else { lastchar=lp; lastin=inp; *lp++ = c; eol=lp; continue; } case MODIFY: case TWO: if (lp>=lplim) break; else { lastchar=lp; lastin=inp; *lp++ = c_MODIFY; *lp++ = (*ter.in_two)(c); eol=lp; continue; } case TAB: if (!tab_preserve) /* UMIST */ { if (lp+8 - ((lp-linebuf+8) % 8) > lplim) break; else { if (lastchar!=0) { lastchar=lp; lastin=inp; } do *lp++ = c_SPACE; while ((lp-linebuf) % 8 != 0); if (lp<=lplim) { lastspace = lp-1; inspace = inp; } continue; } } default: if (c == c_NL) { *eol = '\0'; io_p = inp; return(true); } else if (0 on ITT, * bold-face ^ on Hazeltine */ if (lp>=lplim) break; else { lastchar=lp; lastin=inp; *lp++ = c_CONTROL; *lp++ = (c==0177 ? '?' : 01<=c && c<=032 ? c + 0140 : c + 0100); eol=lp; continue; } } else if (c == 0) continue; /* nulls are ignored */ else (*crash)("input file contains character %8", c&0377); } /* end of switch (ictab) */ /* come here when line is too long to fit on page */ if (lastspace != 0) /* put a zero after the last space or tab */ { lp = lastspace+1; *lp++=c_CONTROL; *lp++='\0'; io_p = inspace; } else if (lastchar != 0) /* put a zero in place of the last character */ { lp = lastchar; *lp++ = c_CONTROL; *lp++ = '\0'; io_p = lastin-1; } else editerror("no last char position [ded_inline]"); if (inp