This is b.c in view mode; [Download] [Up]
/* Editor engine Copyright (C) 1992 Joseph H. Allen This file is part of JOE (Joe's Own Editor) JOE is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. JOE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with JOE; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #ifndef __MSDOS__ #include <pwd.h> #endif #include <errno.h> #include "config.h" #include "blocks.h" #include "undo.h" #include "vs.h" #include "va.h" #include "zstr.h" #include "path.h" #include "w.h" #include "tty.h" #include "scrn.h" #include "main.h" #include "bw.h" #include "uerror.h" #include "b.h" char stdbuf[stdsiz]; extern int errno; int error; int force=0; VFILE *vmem; char *msgs[]= { "Error writing file", "Error opening file", "Error seeking file", "Error reading file", "New File" }; /* Get size of gap (amount of free space) */ #define GGAPSZ(hdr) ((hdr)->ehole-(hdr)->hole) /* Get number of characters in gap buffer */ #define GSIZE(hdr) (SEGSIZ-GGAPSZ(hdr)) /* Set position of gap */ static void gstgap(hdr,ptr,ofst) H *hdr; char *ptr; int ofst; { if(ofst>hdr->hole) mfwrd(ptr+hdr->hole,ptr+hdr->ehole,ofst-hdr->hole), vchanged(ptr); else if(ofst<hdr->hole) mbkwd(ptr+hdr->ehole-(hdr->hole-ofst),ptr+ofst,hdr->hole-ofst), vchanged(ptr); hdr->ehole=ofst+hdr->ehole-hdr->hole; hdr->hole=ofst; } /* Insert a block */ static void ginsm(hdr,ptr,ofst,blk,size) H *hdr; char *ptr; int ofst; char *blk; int size; { if(ofst!=hdr->hole) gstgap(hdr,ptr,ofst); mcpy(ptr+hdr->hole,blk,size); hdr->hole+=size; vchanged(ptr); } /* Read block */ static void grmem(hdr,ptr,ofst,blk,size) H *hdr; char *ptr; int ofst; char *blk; int size; { if(ofst<hdr->hole) if(size>hdr->hole-ofst) mcpy(blk,ptr+ofst,hdr->hole-ofst), mcpy(blk+hdr->hole-ofst,ptr+hdr->ehole,size-(hdr->hole-ofst)); else mcpy(blk,ptr+ofst,size); else mcpy(blk,ptr+ofst+hdr->ehole-hdr->hole,size); } /* Header allocation */ static H nhdrs={{&nhdrs,&nhdrs}}; static H ohdrs={{&ohdrs,&ohdrs}}; static H *halloc() { H *h; if(qempty(H,link,&ohdrs)) { h=(H *)alitem(&nhdrs,sizeof(H)); h->seg=valloc(vmem,(long)SEGSIZ); } else h=deque(H,link,ohdrs.link.next); h->hole=0; h->ehole=SEGSIZ; h->nlines=0; izque(H,link,h); return h; } static void hfree(h) H *h; { enquef(H,link,&ohdrs,h); } static void hfreechn(h) H *h; { splicef(H,link,&ohdrs,h); } /* Pointer allocation */ static P frptrs={{&frptrs,&frptrs}}; static P *palloc() { return alitem(&frptrs,sizeof(P)); } static void pfree(p) P *p; { enquef(P,link,&frptrs,p); } /* Doubly linked list of buffers and free buffer structures */ static B bufs={{&bufs,&bufs}}; static B frebufs={{&frebufs,&frebufs}}; B *bnext() { B *b; do { b=bufs.link.prev; deque(B,link,&bufs); enqueb(B,link,b,&bufs); } while(b->internal); return b; } B *bprev() { B *b; do { b=bufs.link.next; deque(B,link,&bufs); enquef(B,link,b,&bufs); } while(b->internal); return b; } /* Make a buffer out of a chain */ static B *bmkchn(chn,prop,amnt,nlines) H *chn; B *prop; long amnt, nlines; { B *b=alitem(&frebufs,sizeof(B)); b->undo=undomk(b); if(prop) b->o=prop->o; else b->o=pdefault; mset(b->marks,0,sizeof(b->marks)); b->rdonly=0; b->orphan=0; b->oldcur=0; b->oldtop=0; b->backup=1; b->internal=1; b->changed=0; b->count=1; b->name=0; b->er= -3; b->bof=palloc(); izque(P,link,b->bof); b->bof->end=0; b->bof->b=b; b->bof->owner=0; b->bof->hdr=chn; b->bof->ptr=vlock(vmem,b->bof->hdr->seg); b->bof->ofst=0; b->bof->byte=0; b->bof->line=0; b->bof->col=0; b->bof->xcol=0; b->bof->valcol=1; b->eof=pdup(b->bof); b->eof->end=1; vunlock(b->eof->ptr); b->eof->hdr=chn->link.prev; b->eof->ptr=vlock(vmem,b->eof->hdr->seg); b->eof->ofst=GSIZE(b->eof->hdr); b->eof->byte=amnt; b->eof->line=nlines; b->eof->valcol=0; enquef(B,link,&bufs,b); pcoalesce(b->bof); pcoalesce(b->eof); return b; } /* Create an empty buffer */ B *bmk(prop) B *prop; { return bmkchn(halloc(),prop,0L,0L); } /* Eliminate a buffer */ extern B *errbuf; void brm(b) B *b; { if(b && !--b->count) { if(b->changed) abrerr(b->name); if(b==errbuf) errbuf=0; if(b->undo) undorm(b->undo); hfreechn(b->eof->hdr); while(!qempty(P,link,b->bof)) prm(b->bof->link.next); prm(b->bof); if(b->name) free(b->name); demote(B,link,&frebufs,b); } } P *poffline(p) P *p; { if(p->ptr) { vunlock(p->ptr); p->ptr=0; } return p; } P *ponline(p) P *p; { if(!p->ptr) p->ptr=vlock(vmem,p->hdr->seg); return p; } B *boffline(b) B *b; { P *p=b->bof; do poffline(p); while((p=p->link.next)!=b->bof); return b; } B *bonline(b) B *b; { P *p=b->bof; do ponline(p); while((p=p->link.next)!=b->bof); return b; } P *pdup(p) P *p; { P *n=palloc(); n->end=0; n->ptr=0; n->owner=0; enquef(P,link,p,n); return pset(n,p); } P *pdupown(p,o) P *p; P **o; { P *n=palloc(); n->end=0; n->ptr=0; n->owner=o; enquef(P,link,p,n); pset(n,p); if(*o) prm(*o); *o=n; return n; } void prm(p) P *p; { if(!p) return; if(p->owner) *p->owner=0; if(p->ptr) vunlock(p->ptr); pfree(deque(P,link,p)); } P *pset(n,p) P *n, *p; { if(n!=p) { n->b=p->b; n->ofst=p->ofst; n->hdr=p->hdr; if(n->ptr) vunlock(n->ptr); if(p->ptr) { n->ptr=p->ptr; vupcount(n->ptr); } else n->ptr=vlock(vmem,n->hdr->seg); n->byte=p->byte; n->line=p->line; n->col=p->col; n->valcol=p->valcol; } return n; } P *pbof(p) P *p; { return pset(p,p->b->bof); } P *peof(p) P *p; { return pset(p,p->b->eof); } int pisbof(p) P *p; { return p->hdr==p->b->bof->hdr && !p->ofst; } int piseof(p) P *p; { return p->ofst==GSIZE(p->hdr); } int piseol(p) P *p; { int c; if(piseof(p)) return 1; c=brc(p); if(c=='\n') return 1; #ifdef __MSDOS__ if(c=='\r') { P *q=pdup(p); pfwrd(q,1L); if(pgetc(q)=='\n') { prm(q); return 1; } else prm(q); } #endif return 0; } int pisbol(p) P *p; { char c; if(pisbof(p)) return 1; c=prgetc(p); pgetc(p); return c=='\n'; } int pisbow(p) P *p; { P *q=pdup(p); int c=brc(p); int d=prgetc(q); prm(q); if(crest(c) && !crest(d)) return 1; else return 0; } int piseow(p) P *p; { P *q=pdup(p); int d=brc(q); int c=prgetc(q); prm(q); if(crest(c) && !crest(d)) return 1; else return 0; } int pisblank(p) P *p; { P *q=pdup(p); pbol(q); while(cwhite(brc(q))) pgetc(q); if(piseol(q)) { prm(q); return 1; } else { prm(q); return 0; } } long pisindent(p) P *p; { P *q=pdup(p); long col; pbol(q); while(cwhite(brc(q))) pgetc(q); col=q->col; prm(q); return col; } int pnext(p) P *p; { if(p->hdr==p->b->eof->hdr) { p->ofst=GSIZE(p->hdr); return 0; } p->hdr=p->hdr->link.next; p->ofst=0; vunlock(p->ptr); p->ptr=vlock(vmem,p->hdr->seg); return 1; } int pprev(p) P *p; { if(p->hdr==p->b->bof->hdr) { p->ofst=0; return 0; } p->hdr=p->hdr->link.prev; p->ofst=GSIZE(p->hdr); vunlock(p->ptr); p->ptr=vlock(vmem,p->hdr->seg); return 1; } int pgetc(p) P *p; { char c; if(p->ofst==GSIZE(p->hdr)) return MAXINT; if(p->ofst>=p->hdr->hole) c=p->ptr[p->ofst+p->hdr->ehole-p->hdr->hole]; else c=p->ptr[p->ofst]; if(++p->ofst==GSIZE(p->hdr)) pnext(p); ++p->byte; if(c=='\n') ++p->line, p->col=0, p->valcol=1; #ifdef __MSDOS__ else if(c=='\r') { if(brc(p)=='\n') return pgetc(p); else ++p->col; } #endif else { if(c=='\t') p->col+=p->b->o.tab-p->col%p->b->o.tab; else ++p->col; } return c; } P *pfwrd(p,n) P *p; long n; { if(!n) return p; p->valcol=0; do { if(p->ofst==GSIZE(p->hdr)) do { if(!p->ofst) p->byte+=GSIZE(p->hdr), n-=GSIZE(p->hdr), p->line+=p->hdr->nlines; if(!pnext(p)) return 0; } while(n>GSIZE(p->hdr)); if(p->ofst>=p->hdr->hole) { if(p->ptr[p->ofst+p->hdr->ehole-p->hdr->hole]=='\n') ++p->line; } else if(p->ptr[p->ofst]=='\n') ++p->line; ++p->byte; ++p->ofst; } while(--n); if(p->ofst==GSIZE(p->hdr)) pnext(p); return p; } int prgetc1(p) P *p; { unsigned char c; if(!p->ofst) if(!pprev(p)) return MAXINT; --p->ofst; if(p->ofst>=p->hdr->hole) c=p->ptr[p->ofst+p->hdr->ehole-p->hdr->hole]; else c=p->ptr[p->ofst]; --p->byte; if(c=='\n') --p->line, p->valcol=0; else { if(c=='\t') p->valcol=0; --p->col; } return c; } int prgetc(p) P *p; { int c=prgetc1(p); #ifdef __MSDOS__ if(c=='\n') { c=prgetc1(p); if(c=='\r') return '\n'; if(c!=MAXINT) pgetc(p); c='\n'; } #endif return c; } P *pbkwd(p,n) P *p; long n; { if(!n) return p; p->valcol=0; do { if(!p->ofst) do { if(p->ofst) p->byte-=p->ofst, n-=p->ofst, p->line-=p->hdr->nlines; if(!pprev(p)) return 0; } while(n>GSIZE(p->hdr)); --p->ofst; --p->byte; if(p->ofst>=p->hdr->hole) { if(p->ptr[p->ofst+p->hdr->ehole-p->hdr->hole]=='\n') --p->line; } else if(p->ptr[p->ofst]=='\n') --p->line; } while(--n); return p; } P *pgoto(p,loc) P *p; long loc; { if(loc>p->byte) pfwrd(p,loc-p->byte); else if(loc<p->byte) pbkwd(p,p->byte-loc); return p; } P *pfcol(p) P *p; { H *hdr=p->hdr; int ofst=p->ofst; pbol(p); while(p->ofst!=ofst || p->hdr!=hdr) pgetc(p); return p; } P *pbol(p) P *p; { if(pprevl(p)) pgetc(p); p->col=0; p->valcol=1; return p; } P *peol(p) P *p; { #ifdef __MSDOS__ while(!piseol(p)) pgetc(p); #else while(p->ofst!=GSIZE(p->hdr)) { unsigned char c; if(p->ofst>=p->hdr->hole) c=p->ptr[p->ofst+p->hdr->ehole-p->hdr->hole]; else c=p->ptr[p->ofst]; if(c=='\n') break; else { ++p->byte; ++p->ofst; if(c=='\t') p->col+=p->b->o.tab-p->col%p->b->o.tab; else ++p->col; if(p->ofst==GSIZE(p->hdr)) pnext(p); } } #endif return p; } P *pnextl(p) P *p; { char c; do { if(p->ofst==GSIZE(p->hdr)) do { p->byte+=GSIZE(p->hdr)-p->ofst; if(!pnext(p)) return 0; } while(!p->hdr->nlines); if(p->ofst>=p->hdr->hole) c=p->ptr[p->ofst+p->hdr->ehole-p->hdr->hole]; else c=p->ptr[p->ofst]; ++p->byte; ++p->ofst; } while(c!='\n'); ++p->line; p->col=0; p->valcol=1; if(p->ofst==GSIZE(p->hdr)) pnext(p); return p; } P *pprevl(p) P *p; { char c; p->valcol=0; do { if(!p->ofst) do { p->byte-=p->ofst; if(!pprev(p)) return 0; } while(!p->hdr->nlines); --p->ofst; --p->byte; if(p->ofst>=p->hdr->hole) c=p->ptr[p->ofst+p->hdr->ehole-p->hdr->hole]; else c=p->ptr[p->ofst]; } while(c!='\n'); --p->line; #ifdef __MSDOS__ if(c=='\n') { int k=prgetc1(p); if(k!='\r' && k!=MAXINT) pgetc(p); } #endif return p; } P *pline(p,line) P *p; long line; { if(line>p->b->eof->line) { pset(p,p->b->eof); return p; } if(line<Labs(p->line-line)) pset(p,p->b->bof); if(Labs(p->b->eof->line-line)<Labs(p->line-line)) pset(p,p->b->eof); if(p->line==line) { pbol(p); return p; } while(line>p->line) pnextl(p); if(line<p->line) { while(line<p->line) pprevl(p); pbol(p); } return p; } P *pcol(p,goalcol) P *p; long goalcol; { pbol(p); do { unsigned char c; int wid; if(p->ofst==GSIZE(p->hdr)) break; if(p->ofst>=p->hdr->hole) c=p->ptr[p->ofst+p->hdr->ehole-p->hdr->hole]; else c=p->ptr[p->ofst]; if(c=='\n') break; #ifdef __MSDOS__ if(c=='\r' && piseol(p)) break; #endif if(c=='\t') wid=p->b->o.tab-p->col%p->b->o.tab; else wid=1; if(p->col+wid>goalcol) break; if(++p->ofst==GSIZE(p->hdr)) pnext(p); ++p->byte; p->col+=wid; } while(p->col!=goalcol); return p; } P *pcolwse(p,goalcol) P *p; long goalcol; { int c; pcol(p,goalcol); do c=prgetc(p); while(c==' ' || c=='\t'); if(c!=MAXINT) pgetc(p); return p; } P *pcoli(p,goalcol) P *p; long goalcol; { pbol(p); while(p->col<goalcol) { unsigned char c; if(p->ofst==GSIZE(p->hdr)) break; if(p->ofst>=p->hdr->hole) c=p->ptr[p->ofst+p->hdr->ehole-p->hdr->hole]; else c=p->ptr[p->ofst]; if(c=='\n') break; #ifdef __MSDOS if(c=='\r' && piseol(p)) break; #endif else if(c=='\t') p->col+=p->b->o.tab-p->col%p->b->o.tab; else ++p->col; if(++p->ofst==GSIZE(p->hdr)) pnext(p); ++p->byte; } return p; } void pfill(p,to,usetabs) P *p; long to; { piscol(p); if(usetabs) while(p->col<to) if(p->col+p->b->o.tab-p->col%p->b->o.tab<=to) binsc(p,'\t'), pgetc(p); else binsc(p,' '), pgetc(p); else while(p->col<to) binsc(p,' '), pgetc(p); } void pbackws(p) P *p; { int c; P *q=pdup(p); do c=prgetc(q); while(c==' ' || c=='\t'); if(c!=MAXINT) pgetc(q); bdel(q,p); prm(q); } static char frgetc(p) P *p; { if(!p->ofst) pprev(p); --p->ofst; if(p->ofst>=p->hdr->hole) return p->ptr[p->ofst+p->hdr->ehole-p->hdr->hole]; else return p->ptr[p->ofst]; } static void ffwrd(p,n) P *p; { while(n>GSIZE(p->hdr)-p->ofst) { n-=GSIZE(p->hdr)-p->ofst; if(!pnext(p)) return; } if((p->ofst+=n)==GSIZE(p->hdr)) pnext(p); } static P *ffind(p,s,len) P *p; unsigned char *s; { long amnt=p->b->eof->byte-p->byte; int x; unsigned char table[256], c; if(len>amnt) return 0; if(!len) return p; p->valcol=0; mset(table,255,256); for(x=0;x!=len-1;++x) table[s[x]]=x; ffwrd(p,len); amnt-=len; x=len; do if((c=frgetc(p))!=s[--x]) { if(table[c]==255) ffwrd(p,len+1), amnt-=x+1; else if(x<=table[c]) ffwrd(p,len-x+1), --amnt; else ffwrd(p,len-table[c]), amnt-=x-table[c]; if(amnt<0) return 0; else x=len; } while(x); return p; } static P *fifind(p,s,len) P *p; unsigned char *s; { long amnt=p->b->eof->byte-p->byte; int x; unsigned char table[256], c; if(len>amnt) return 0; if(!len) return p; p->valcol=0; mset(table,255,256); for(x=0;x!=len-1;++x) table[s[x]]=x; ffwrd(p,len); amnt-=len; x=len; do if((c=toup(frgetc(p)))!=s[--x]) { if(table[c]==255) ffwrd(p,len+1), amnt-=x+1; else if(x<=table[c]) ffwrd(p,len-x+1), --amnt; else ffwrd(p,len-table[c]), amnt-=x-table[c]; if(amnt<0) return 0; else x=len; } while(x); return p; } static P *getto(p,q) P *p, *q; { while(p->hdr!=q->hdr || p->ofst!=q->ofst) { if(p->ofst>=p->hdr->hole) { if(p->ptr[p->ofst+p->hdr->ehole-p->hdr->hole]=='\n') ++p->line; } else if(p->ptr[p->ofst]=='\n') ++p->line; ++p->byte; ++p->ofst; if(p->ofst==GSIZE(p->hdr)) pnext(p); while(!p->ofst && p->hdr!=q->hdr) { p->byte+=GSIZE(p->hdr), p->line+=p->hdr->nlines; pnext(p); } } return p; } P *pfind(p,s,len) P *p; char *s; { P *q=pdup(p); if(ffind(q,s,len)) { getto(p,q); prm(q); return p; } else { prm(q); return 0; } } P *pifind(p,s,len) P *p; char *s; { P *q=pdup(p); if(fifind(q,s,len)) { getto(p,q); prm(q); return p; } else { prm(q); return 0; } } static void fbkwd(p,n) P *p; { while(n>p->ofst) { n-=p->ofst; if(!pprev(p)) return; } if(p->ofst>=n) p->ofst-=n; else p->ofst=0; } static int fpgetc(p) P *p; { char c; if(p->ofst==GSIZE(p->hdr)) return MAXINT; if(p->ofst>=p->hdr->hole) c=p->ptr[p->ofst+p->hdr->ehole-p->hdr->hole]; else c=p->ptr[p->ofst]; if(++p->ofst==GSIZE(p->hdr)) pnext(p); return c; } static P *frfind(p,s,len) P *p; unsigned char *s; { long amnt=p->byte; int x; unsigned char table[256], c; if(len>p->b->eof->byte-p->byte) { x=len-(p->b->eof->byte-p->byte); if(amnt<x) return 0; amnt-=x; fbkwd(p,x); } if(!len) return p; p->valcol=0; mset(table,255,256); for(x=len;--x;table[s[x]]=len-x-1); x=0; do if((c=fpgetc(p))!=s[x++]) { if(table[c]==255) fbkwd(p,len+1), amnt-=len-x+1; else if(len-table[c]<=x) fbkwd(p,x+1), --amnt; else fbkwd(p,len-table[c]), amnt-=len-table[c]-x; if(amnt<0) return 0; else x=0; } while(x!=len); fbkwd(p,len); return p; } static P *frifind(p,s,len) P *p; unsigned char *s; { long amnt=p->byte; int x; unsigned char table[256], c; if(len>p->b->eof->byte-p->byte) { x=len-(p->b->eof->byte-p->byte); if(amnt<x) return 0; amnt-=x; fbkwd(p,x); } if(!len) return p; p->valcol=0; mset(table,255,256); for(x=len;--x;table[s[x]]=len-x-1); x=0; do if((c=toup(fpgetc(p)))!=s[x++]) { if(table[c]==255) fbkwd(p,len+1), amnt-=len-x+1; else if(len-table[c]<=x) fbkwd(p,x+1), --amnt; else fbkwd(p,len-table[c]), amnt-=len-table[c]-x; if(amnt<0) return 0; else x=0; } while(x!=len); fbkwd(p,len); return p; } static P *rgetto(p,q) P *p, *q; { while(p->hdr!=q->hdr || p->ofst!=q->ofst) { if(!p->ofst) do { if(p->ofst) p->byte-=p->ofst, p->line-=p->hdr->nlines; pprev(p); } while(p->hdr!=q->hdr); --p->ofst; --p->byte; if(p->ofst>=p->hdr->hole) { if(p->ptr[p->ofst+p->hdr->ehole-p->hdr->hole]=='\n') --p->line; } else if(p->ptr[p->ofst]=='\n') --p->line; } return p; } P *prfind(p,s,len) P *p; char *s; { P *q=pdup(p); if(frfind(q,s,len)) { rgetto(p,q); prm(q); return p; } else { prm(q); return 0; } } P *prifind(p,s,len) P *p; char *s; { P *q=pdup(p); if(frifind(q,s,len)) { rgetto(p,q); prm(q); return p; } else { prm(q); return 0; } } B *bcpy(from,to) P *from, *to; { H anchor, *l; char *ptr; P *q; if(from->byte>=to->byte) return bmk(from->b); q=pdup(from); izque(H,link,&anchor); if(q->hdr==to->hdr) { l=halloc(); ptr=vlock(vmem,l->seg); if(q->ofst!=q->hdr->hole) gstgap(q->hdr,q->ptr,q->ofst); l->nlines=mcnt(q->ptr+q->hdr->ehole,'\n',l->hole=to->ofst-q->ofst); mcpy(ptr,q->ptr+q->hdr->ehole,l->hole); vchanged(ptr); vunlock(ptr); enqueb(H,link,&anchor,l); } else { l=halloc(); ptr=vlock(vmem,l->seg); if(q->ofst!=q->hdr->hole) gstgap(q->hdr,q->ptr,q->ofst); l->nlines=mcnt(q->ptr+q->hdr->ehole,'\n',l->hole=SEGSIZ-q->hdr->ehole); mcpy(ptr,q->ptr+q->hdr->ehole,l->hole); vchanged(ptr); vunlock(ptr); enqueb(H,link,&anchor,l); pnext(q); while(q->hdr!=to->hdr) { l=halloc(); ptr=vlock(vmem,l->seg); l->nlines=q->hdr->nlines; mcpy(ptr,q->ptr,q->hdr->hole); mcpy(ptr+q->hdr->hole,q->ptr+q->hdr->ehole,SEGSIZ-q->hdr->ehole); l->hole=GSIZE(q->hdr); vchanged(ptr); vunlock(ptr); enqueb(H,link,&anchor,l); pnext(q); } if(to->ofst) { l=halloc(); ptr=vlock(vmem,l->seg); if(to->ofst!=to->hdr->hole) gstgap(to->hdr,to->ptr,to->ofst); l->nlines=mcnt(to->ptr,'\n',to->ofst); mcpy(ptr,to->ptr,l->hole=to->ofst); vchanged(ptr); vunlock(ptr); enqueb(H,link,&anchor,l); } } l=anchor.link.next; deque(H,link,&anchor); prm(q); return bmkchn(l,from->b,to->byte-from->byte,to->line-from->line); } /* Coalesce small blocks into a single larger one */ void pcoalesce(p) P *p; { if(p->hdr!=p->b->eof->hdr && GSIZE(p->hdr)+GSIZE(p->hdr->link.next)<=SEGSIZ-SEGSIZ/4) { H *hdr=p->hdr->link.next; char *ptr=vlock(vmem,hdr->seg); int osize=GSIZE(p->hdr); int size=GSIZE(hdr); P *q; gstgap(hdr,ptr,size); ginsm(p->hdr,p->ptr,GSIZE(p->hdr),ptr,size); p->hdr->nlines+=hdr->nlines; vunlock(ptr); hfree(deque(H,link,hdr)); for(q=p->link.next;q!=p;q=q->link.next) if(q->hdr==hdr) { q->hdr=p->hdr; if(q->ptr) { vunlock(q->ptr); q->ptr=vlock(vmem,q->hdr->seg); } q->ofst+=osize; } } if(p->hdr!=p->b->bof->hdr && GSIZE(p->hdr)+GSIZE(p->hdr->link.prev)<=SEGSIZ-SEGSIZ/4) { H *hdr=p->hdr->link.prev; char *ptr=vlock(vmem,hdr->seg); int size=GSIZE(hdr); P *q; gstgap(hdr,ptr,size); ginsm(p->hdr,p->ptr,0,ptr,size); p->hdr->nlines+=hdr->nlines; vunlock(ptr); hfree(deque(H,link,hdr)); p->ofst+=size; for(q=p->link.next;q!=p;q=q->link.next) if(q->hdr==hdr) { q->hdr=p->hdr; if(q->ptr) vunlock(q->ptr); q->ptr=vlock(vmem,q->hdr->seg); } else if(q->hdr==p->hdr) q->ofst+=size; } } /* Delete the text between two pointers from a buffer and return it in a new * buffer. * * This routine calls these functions: * gstgap - to position gaps * halloc - to allocate new header/segment pairs * vlock - virtual memory routines * vunlock * vchanged * vupcount * mcpy - to copy deleted text * mcnt - to count NLs * snip - queue routines * enqueb * splicef * scrdel - to tell screen update to scroll when NLs are deleted * bmkchn - to make a buffer out of a chain */ /* This is only to be used for bdel() */ static B *bcut(from,to) P *from, *to; { H *h, /* The deleted text */ *i; char *ptr; P *p; long nlines; /* No. EOLs to delete */ long amnt; /* No. bytes to delete */ int toamnt; /* Amount to delete from segment in 'to' */ int bofmove=0; /* Set if bof got deleted */ if(!(amnt=to->byte-from->byte)) return 0; /* ...nothing to delete */ nlines=to->line-from->line; if(from->hdr==to->hdr) { /* Delete is within a single segment */ /* Move gap to deletion point */ if(from->ofst!=from->hdr->hole) gstgap(from->hdr,from->ptr,from->ofst); /* Store the deleted text */ h=halloc(); ptr=vlock(vmem,h->seg); mcpy(ptr,from->ptr+from->hdr->ehole,(int)amnt); h->hole=amnt; h->nlines=nlines; vchanged(ptr); vunlock(ptr); /* Delete */ from->hdr->ehole+=amnt; from->hdr->nlines-=nlines; toamnt=amnt; } else { /* Delete crosses segments */ H *a; if(toamnt=to->ofst) { /* Delete beginning of to */ /* Move gap to deletion point */ /* To could be deleted if it's at the end of the file */ if(to->ofst!=to->hdr->hole) gstgap(to->hdr,to->ptr,to->ofst); /* Save deleted text */ i=halloc(); ptr=vlock(vmem,i->seg); mcpy(ptr,to->ptr,to->hdr->hole); i->hole=to->hdr->hole; i->nlines=mcnt(to->ptr,'\n',to->hdr->hole); vchanged(ptr); vunlock(ptr); /* Delete */ to->hdr->nlines-=i->nlines; to->hdr->hole=0; } else i=0; /* Delete end of from */ if(!from->ofst) { /* ..unless from needs to be deleted too */ a=from->hdr->link.prev, h=0; if(a==from->b->eof->hdr) bofmove=1; } else { a=from->hdr; /* Move gap to deletion point */ if(from->ofst!=from->hdr->hole) gstgap(from->hdr,from->ptr,from->ofst); /* Save deleted text */ h=halloc(); ptr=vlock(vmem,h->seg); mcpy(ptr,from->ptr+from->hdr->ehole,SEGSIZ-from->hdr->ehole); h->hole=SEGSIZ-from->hdr->ehole; h->nlines=mcnt(ptr,'\n',h->hole); vchanged(ptr); vunlock(ptr); /* Delete */ from->hdr->nlines-=h->nlines; from->hdr->ehole=SEGSIZ; } /* Make from point to header/segment of to */ from->hdr=to->hdr; vunlock(from->ptr); from->ptr=to->ptr; vupcount(to->ptr); from->ofst=0; /* Delete headers/segments between a and to->hdr (if there are any) */ if(a->link.next!=to->hdr) if(!h) { h=snip(H,link,a->link.next,to->hdr->link.prev); if(i) enqueb(H,link,h,i); } else { splicef(H,link,h,snip(H,link,a->link.next,to->hdr->link.prev)); if(i) enqueb(H,link,h,i); } else if(!h) h=i; else if(i) enqueb(H,link,h,i); } /* If to is empty, then it must have been at the end of the file. If the file did not become empty, delete to */ if(!GSIZE(to->hdr) && from->byte) { H *ph=from->hdr->link.prev; hfree(deque(H,link,from->hdr)); vunlock(from->ptr); from->hdr=ph; from->ptr=vlock(vmem,from->hdr->seg); from->ofst=GSIZE(ph); vunlock(from->b->eof->ptr); from->b->eof->ptr=from->ptr; vupcount(from->ptr); from->b->eof->hdr=from->hdr; from->b->eof->ofst=from->ofst; } /* The deletion is now done */ /* Scroll if necessary */ if(bofmove) pset(from->b->bof,from); if(nlines && !pisbol(from)) { scrdel(from->b,from->line,nlines,1); delerr(from->b->name,from->line,nlines,0); } else { scrdel(from->b,from->line,nlines,0); delerr(from->b->name,from->line,nlines,1); } /* Fix pointers */ for(p=from->link.next;p!=from;p=p->link.next) if(p->line==from->line && p->byte>from->byte) p->valcol=0; for(p=from->link.next;p!=from;p=p->link.next) if(p->byte>=from->byte) if(p->byte<=from->byte+amnt) if(p->ptr) pset(p,from); else poffline(pset(p,from)); else { if(p->hdr==to->hdr) p->ofst-=toamnt; p->byte-=amnt; p->line-=nlines; } pcoalesce(from); /* Make buffer out of deleted text and return it */ return bmkchn(h,from->b,amnt,nlines); } void bdel(from,to) P *from, *to; { if(to->byte-from->byte) { B *b=bcut(from,to); if(from->b->undo) undodel(from->b->undo,from->byte,b); else brm(b); from->b->changed=1; } } /* Split a block at p's ofst */ /* p is placed in the new block such that it points to the same text but with * p->ofst==0 */ static void bsplit(p) P *p; { if(p->ofst) { H *hdr; char *ptr; P *pp; hdr=halloc(); ptr=vlock(vmem,hdr->seg); if(p->ofst!=p->hdr->hole) gstgap(p->hdr,p->ptr,p->ofst); mcpy(ptr,p->ptr+p->hdr->ehole,SEGSIZ-p->hdr->ehole); hdr->hole=SEGSIZ-p->hdr->ehole; hdr->nlines=mcnt(ptr,'\n',hdr->hole); p->hdr->nlines-=hdr->nlines; vchanged(ptr); p->hdr->ehole=SEGSIZ; enquef(H,link,p->hdr,hdr); vunlock(p->ptr); for(pp=p->link.next;pp!=p;pp=pp->link.next) if(pp->hdr==p->hdr && pp->ofst>=p->ofst) { pp->hdr=hdr; if(pp->ptr) { vunlock(pp->ptr); pp->ptr=ptr; vupcount(ptr); } pp->ofst-=p->ofst; } p->ptr=ptr; p->hdr=hdr; p->ofst=0; } } /* Make a chain out of a block of memory */ /* The block must not be empty */ static H *bldchn(blk,size,nlines) char *blk; int size; long *nlines; { H anchor, *l; *nlines=0; izque(H,link,&anchor); do { char *ptr; int amnt; ptr=vlock(vmem,(l=halloc())->seg); if(size>SEGSIZ) amnt=SEGSIZ; else amnt=size; mcpy(ptr,blk,amnt); l->hole=amnt; l->ehole=SEGSIZ; (*nlines)+=(l->nlines=mcnt(ptr,'\n',amnt)); vchanged(ptr); vunlock(ptr); enqueb(H,link,&anchor,l); blk+=amnt; size-=amnt; } while(size); l=anchor.link.next; deque(H,link,&anchor); return l; } /* Insert a chain into a buffer */ /* This does not update pointers */ static void inschn(p,a) P *p; H *a; { if(!p->b->eof->byte) { /* P's buffer is empty: replace the empty segment in p with a */ hfree(p->hdr); p->hdr=a; vunlock(p->ptr); p->ptr=vlock(vmem,a->seg); pset(p->b->bof,p); p->b->eof->hdr=a->link.prev; vunlock(p->b->eof->ptr); p->b->eof->ptr=vlock(vmem,p->b->eof->hdr->seg); p->b->eof->ofst=GSIZE(p->b->eof->hdr); } else if(piseof(p)) { /* We're at the end of the file: append a to the file */ p->b->eof->hdr=a->link.prev; spliceb(H,link,p->b->bof->hdr,a); vunlock(p->b->eof->ptr); p->b->eof->ptr=vlock(vmem,p->b->eof->hdr->seg); p->b->eof->ofst=GSIZE(p->b->eof->hdr); p->hdr=a; vunlock(p->ptr); p->ptr=vlock(vmem,p->hdr->seg); p->ofst=0; } else if(pisbof(p)) { /* We're at the beginning of the file: insert chain and set bof pointer */ p->hdr=spliceb(H,link,p->hdr,a); vunlock(p->ptr); p->ptr=vlock(vmem,a->seg); pset(p->b->bof,p); } else { /* We're in the middle of the file: split and insert */ bsplit(p); p->hdr=spliceb(H,link,p->hdr,a); vunlock(p->ptr); p->ptr=vlock(vmem,a->seg); } } static void fixupins(p,amnt,nlines,hdr,hdramnt) P *p; long amnt; long nlines; H *hdr; int hdramnt; { P *pp; if(nlines && !pisbol(p)) scrins(p->b,p->line,nlines,1); else scrins(p->b,p->line,nlines,0); inserr(p->b->name,p->line,nlines); for(pp=p->link.next;pp!=p;pp=pp->link.next) if(pp->line==p->line && (pp->byte>p->byte || pp->end && pp->byte==p->byte)) pp->valcol=0; for(pp=p->link.next;pp!=p;pp=pp->link.next) if(pp->byte==p->byte && !pp->end) if(pp->ptr) pset(pp,p); else poffline(pset(pp,p)); else if(pp->byte>p->byte || pp->end && pp->byte==p->byte) { pp->byte+=amnt; pp->line+=nlines; if(pp->hdr==hdr) pp->ofst+=hdramnt; } if(p->b->undo) undoins(p->b->undo,p,amnt); p->b->changed=1; } /* Insert a buffer at pointer position */ /* The buffer goes away */ P *binsb(p,b) P *p; B *b; { if(b->eof->byte) { P *q=pdup(p); inschn(q,b->bof->hdr); b->eof->hdr=halloc(); fixupins(q,b->eof->byte,b->eof->line,NULL,0); pcoalesce(q); prm(q); } brm(b); return p; } P *binsm(p,blk,amnt) P *p; char *blk; int amnt; { long nlines; H *h=0; int hdramnt; P *q; if(!amnt) return p; q=pdup(p); if(amnt<=GGAPSZ(q->hdr)) { h=q->hdr; hdramnt=amnt; ginsm(q->hdr,q->ptr,q->ofst,blk,amnt); q->hdr->nlines+=(nlines=mcnt(blk,'\n',amnt)); } else if(!q->ofst && q->hdr!=q->b->bof->hdr && amnt<=GGAPSZ(q->hdr->link.prev)) { pprev(q); ginsm(q->hdr,q->ptr,q->ofst,blk,amnt); q->hdr->nlines+=(nlines=mcnt(blk,'\n',amnt)); } else { H *a=bldchn(blk,amnt,&nlines); inschn(q,a); } fixupins(q,(long)amnt,nlines,h,hdramnt); pcoalesce(q); prm(q); return p; } P *binsc(p,c) P *p; char c; { #ifdef __MSDOS__ if(c=='\n') return binsm(p,"\r\n",2); else #endif return binsm(p,&c,1); } P *binss(p,s) P *p; char *s; { return binsm(p,s,zlen(s)); } /* Read 'size' bytes from file or stream. Stops and returns amnt. read * when requested size has been read or when end of file condition occurs. * Returns with -2 in error for read error or 0 in error for success. */ static int bkread(fi,buff,size) char *buff; { int a,b; if(!size) { error=0; return 0; } for(a=b=0;(a<size) && ((b=jread(fi,buff+a,size-a))>0);a+=b); if(b<0) error= -2; else error=0; return a; } /* Read up to 'max' bytes from a file into a buffer */ /* Returns with 0 in error or -2 in error for read error */ B *bread(fi,max) long max; { H anchor, *l; long lines=0, total=0; int amnt; char *seg; izque(H,link,&anchor); error=0; while(seg=vlock(vmem,(l=halloc())->seg), !error && (amnt=bkread(fi,seg,max>=SEGSIZ?SEGSIZ:(int)max))) { total+=amnt; max-=amnt; l->hole=amnt; lines+=(l->nlines=mcnt(seg,'\n',amnt)); vchanged(seg); vunlock(seg); enqueb(H,link,&anchor,l); } hfree(l); vunlock(seg); if(!total) return bmk(NULL); l=anchor.link.next; deque(H,link,&anchor); return bmkchn(l,NULL,total,lines); } /* Parse file name. * * Removes ',xxx,yyy' from end of name and puts their value into skip and amnt * Replaces ~user/ with directory of given user * Replaces ~/ with $HOME * * Returns new variable length string. */ char *parsens(s,skip,amnt) char *s; long *skip, *amnt; { char *n=vsncpy(NULL,0,sz(s)); int x; *skip=0; *amnt= MAXLONG; for(x=sLEN(n)-1;x>0 && (n[x]>='0' && n[x]<='9' || n[x]=='x' || n[x]=='X');--x); if(n[x]==',') { n[x]=0; if(n[x+1]=='x' || n[x+1]=='X') sscanf(n+x+2,"%lx",skip); else if(n[x+1]=='0' && (n[x+2]=='x' || n[x+2]=='X')) sscanf(n+x+3,"%lx",skip); else if(n[x+1]=='0') sscanf(n+x+1,"%lo",skip); else sscanf(n+x+1,"%ld",skip); for(--x;x>0 && (n[x]>='0' && n[x]<='9' || n[x]=='x' || n[x]=='X');--x); if(n[x]==',') { n[x]=0; *amnt= *skip; if(n[x+1]=='x' || n[x+1]=='X') sscanf(n+x+2,"%lx",skip); else if(n[x+1]=='0' && (n[x+2]=='x' || n[x+2]=='X')) sscanf(n+x+3,"%lx",skip); else if(n[x+1]=='0') sscanf(n+x+1,"%lo",skip); else sscanf(n+x+1,"%ld",skip); } } #ifndef __MSDOS__ if(n[0]=='~') { for(x=1;n[x] && n[x]!='/';++x); if(n[x]=='/') if(x==1) { char *z; s=getenv("HOME"); z=vsncpy(NULL,0,sz(s)); z=vsncpy(z,sLEN(z),sz(n+x)); vsrm(n); n=z; } else { struct passwd *passwd; n[x]=0; passwd=getpwnam(n+1); n[x]='/'; if(passwd) { char *z=vsncpy(NULL,0,sz(passwd->pw_dir)); z=vsncpy(z,sLEN(z),sz(n+x)); vsrm(n); n=z; } } } #endif return n; } /* Load file into new buffer and return the new buffer */ /* Returns with error set to 0 for success, * -1 for new file (file doesn't exist) * -2 for read error * -3 for seek error * -4 for open error */ B *bload(s) char *s; { char buffer[SEGSIZ]; FILE *fi; B *b; long skip,amnt; char *n; if(!s || !s[0]) { error= -1; b=bmk(NULL); setopt(&b->o,""); b->rdonly=b->o.readonly; b->er=error; return b; } n=parsens(s,&skip,&amnt); /* Open file or stream */ ossep(n); #ifndef __MSDOS__ if(n[0]=='!') { nescape(maint->t); ttclsn(); fi=popen(n+1,"r"); } else #endif if(!zcmp(n,"-")) fi=stdin; else fi=fopen(n,"r"); joesep(n); /* Abort if couldn't open */ if(!fi) { if(errno==ENOENT) error= -1; else error= -4; b=bmk(NULL); setopt(&b->o,n); b->rdonly=b->o.readonly; goto opnerr; } /* Skip data if we need to */ if(skip && lseek(fileno(fi),skip,0)<0) { int r; while(skip>SEGSIZ) { r=bkread(fileno(fi),buffer,SEGSIZ); if(r!=SEGSIZ || error) { error= -3; goto err; } skip-=SEGSIZ; } skip-=bkread(fileno(fi),buffer,(int)skip); if(skip || error) { error= -3; goto err; } } /* Read from stream into new buffer */ b=bread(fileno(fi),amnt); setopt(&b->o,n); b->rdonly=b->o.readonly; /* Close stream */ err:; #ifndef __MSDOS__ if(s[0]=='!') pclose(fi); else #endif if(zcmp(n,"-")) fclose(fi); opnerr:; if(s[0]=='!') ttopnn(), nreturn(maint->t); /* Set name */ b->name=joesep(zdup(s)); /* Set flags */ if(error || s[0]=='!' || skip || amnt!=MAXLONG) b->backup=1, b->changed=0; else if(!zcmp(n,"-")) b->backup=1, b->changed=1; else b->backup=0, b->changed=0; /* Eliminate parsed name */ vsrm(n); b->er=error; return b; } /* Find already loaded buffer or load file into new buffer */ B *bfind(s) char *s; { B *b; if(!s || !s[0]) { error= -1; b=bmk(NULL); setopt(&b->o,""); b->rdonly=b->o.readonly; b->internal=0; b->er=error; return b; } for(b=bufs.link.next;b!=&bufs;b=b->link.next) if(b->name && !zcmp(s,b->name)) { if(!b->orphan) ++b->count; else b->orphan=0; error=0; b->internal=0; return b; } b=bload(s); b->internal=0; return b; } char **getbufs() { char **s=vamk(16); B *b; for(b=bufs.link.next;b!=&bufs;b=b->link.next) if(b->name) s=vaadd(s,vsncpy(NULL,0,sz(b->name))); return s; } /* Find an orphaned buffer */ B *borphan() { B *b; for(b=bufs.link.next;b!=&bufs;b=b->link.next) if(b->orphan) { b->orphan=0; return b; } return 0; } /* Write 'size' bytes from file beginning at 'p' to open file 'fd'. * Returns error. * error is set to -5 for write error or 0 for success. * Don't attempt to write past the end of the file */ int bsavefd(p,fd,size) P *p; long size; { P *np=pdup(p); int amnt; while(size>(amnt=GSIZE(np->hdr)-np->ofst)) { if(np->ofst<np->hdr->hole) { if(jwrite(fd,np->ptr+np->ofst,np->hdr->hole-np->ofst)<0) goto err; if(jwrite(fd,np->ptr+np->hdr->ehole,SEGSIZ-np->hdr->ehole)<0) goto err; } else if(jwrite(fd,np->ptr+np->ofst+GGAPSZ(np->hdr),amnt)<0) goto err; size-=amnt; pnext(np); } if(size) if(np->ofst<np->hdr->hole) if(size>np->hdr->hole-np->ofst) { if(jwrite(fd,np->ptr+np->ofst,np->hdr->hole-np->ofst)<0) goto err; if(jwrite(fd,np->ptr+np->hdr->ehole,(int)size-np->hdr->hole+np->ofst)<0) goto err; } else { if(jwrite(fd,np->ptr+np->ofst,(int)size)<0) goto err; } else if(jwrite(fd,np->ptr+np->ofst+GGAPSZ(np->hdr),(int)size)<0) goto err; prm(np); return error=0; err:; prm(np); return error=5; } /* Save 'size' bytes beginning at 'p' in file 's' */ int bsave(p,s,size) P *p; char *s; long size; { FILE *f; long skip,amnt; s=parsens(s,&skip,&amnt); if(amnt<size) size=amnt; ossep(s); #ifndef __MSDOS__ if(s[0]=='!') { nescape(maint->t); ttclsn(); f=popen(s+1,"w"); } else #endif if(s[0]=='>' && s[1]=='>') f=fopen(s+2,"a"); else if(!zcmp(s,"-")) { nescape(maint->t); ttclsn(); f=stdout; } else if(skip || amnt!=MAXLONG) f=fopen(s,"r+"); else f=fopen(s,"w"); joesep(s); if(!f) { error= -4; goto opnerr; } fflush(f); if(skip && lseek(fileno(f),skip,0)<0) { error= -3; goto err; } bsavefd(p,fileno(f),size); if(!error && force && size && !skip && amnt==MAXLONG) { P *q=pdup(p); char nl='\n'; pfwrd(q,size-1); if(brc(q)!='\n' && jwrite(fileno(f),&nl,1)<0) error= -5; prm(q); } err:; #ifndef __MSDOS__ if(s[0]=='!') pclose(f); else #endif if(zcmp(s,"-")) fclose(f); else fflush(f); opnerr:; if(s[0]=='!' || !zcmp(s,"-")) ttopnn(), nreturn(maint->t); return error; } int brc(p) P *p; { if(p->ofst==GSIZE(p->hdr)) return MAXINT; if(p->ofst>=p->hdr->hole) return p->ptr[p->ofst+p->hdr->ehole-p->hdr->hole]; else return p->ptr[p->ofst]; } char *brmem(p,blk,size) P *p; char *blk; int size; { char *bk=blk; P *np; int amnt; np=pdup(p); while(size>(amnt=GSIZE(np->hdr)-np->ofst)) { grmem(np->hdr,np->ptr,np->ofst,bk,amnt); bk+=amnt; size-=amnt; pnext(np); } if(size) grmem(np->hdr,np->ptr,np->ofst,bk,size); prm(np); return blk; } char *brs(p,size) P *p; int size; { char *s=(char *)malloc(size+1); s[size]=0; return brmem(p,s,size); } char *brvs(p,size) P *p; int size; { char *s=vstrunc(NULL,size); return brmem(p,s,size); } /* Save edit buffers when editor dies */ extern char *ctime(); void ttsig(sig) { long tim=time(0); B *b; FILE *f=fopen("DEADJOE","a"); fprintf(f,"\n*** Modified files in JOE when it aborted on %s",ctime(&tim)); if(sig) fprintf(f,"*** JOE was aborted by signal %d\n",sig); else fprintf(f,"*** JOE was aborted because the terminal closed\n"); fflush(f); for(b=bufs.link.next;b!=&bufs;b=b->link.next) if(b->changed) { if(b->name) fprintf(f,"\n*** File \'%s\'\n",b->name); else fprintf(f,"\n*** File \'(Unnamed)\'\n"); fflush(f); bsavefd(b->bof,fileno(f),b->eof->byte); } if(sig) ttclsn(); _exit(1); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.