⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ecmd.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
voidprintposn(Text *t, int charsonly){	long l1, l2;	if (t != nil && t->file != nil && t->file->name != nil)		warning(nil, "%.*S:", t->file->nname, t->file->name);	if(!charsonly){		l1 = 1+nlcount(t, 0, addr.r.q0);		l2 = l1+nlcount(t, addr.r.q0, addr.r.q1);		/* check if addr ends with '\n' */		if(addr.r.q1>0 && addr.r.q1>addr.r.q0 && textreadc(t, addr.r.q1-1)=='\n')			--l2;		warning(nil, "%lud", l1);		if(l2 != l1)			warning(nil, ",%lud", l2);		warning(nil, "\n");		return;	}	warning(nil, "#%d", addr.r.q0);	if(addr.r.q1 != addr.r.q0)		warning(nil, ",#%d", addr.r.q1);	warning(nil, "\n");}inteq_cmd(Text *t, Cmd *cp){	int charsonly;	switch(cp->text->n){	case 0:		charsonly = FALSE;		break;	case 1:		if(cp->text->r[0] == '#'){			charsonly = TRUE;			break;		}	default:		SET(charsonly);		editerror("newline expected");	}	printposn(t, charsonly);	return TRUE;}intnl_cmd(Text *t, Cmd *cp){	Address a;	File *f;	f = t->file;	if(cp->addr == 0){		/* First put it on newline boundaries */		mkaddr(&a, f);		addr = lineaddr(0, a, -1);		a = lineaddr(0, a, 1);		addr.r.q1 = a.r.q1;		if(addr.r.q0==t->q0 && addr.r.q1==t->q1){			mkaddr(&a, f);			addr = lineaddr(1, a, 1);		}	}	textshow(t, addr.r.q0, addr.r.q1, 1);	return TRUE;}intappend(File *f, Cmd *cp, long p){	if(cp->text->n > 0)		eloginsert(f, p, cp->text->r, cp->text->n);	f->curtext->q0 = p;	f->curtext->q1 = p;	return TRUE;}intpdisplay(File *f){	long p1, p2;	int np;	Rune *buf;	p1 = addr.r.q0;	p2 = addr.r.q1;	if(p2 > f->nc)		p2 = f->nc;	buf = fbufalloc();	while(p1 < p2){		np = p2-p1;		if(np>RBUFSIZE-1)			np = RBUFSIZE-1;		bufread(f, p1, buf, np);		buf[np] = L'\0';		warning(nil, "%S", buf);		p1 += np;	}	fbuffree(buf);	f->curtext->q0 = addr.r.q0;	f->curtext->q1 = addr.r.q1;	return TRUE;}voidpfilename(File *f){	int dirty;	Window *w;	w = f->curtext->w;	/* same check for dirty as in settag, but we know ncache==0 */	dirty = !w->isdir && !w->isscratch && f->mod;	warning(nil, "%c%c%c %.*S\n", " '"[dirty],		'+', " ."[curtext!=nil && curtext->file==f], f->nname, f->name);}voidloopcmd(File *f, Cmd *cp, Range *rp, long nrp){	long i;	for(i=0; i<nrp; i++){		f->curtext->q0 = rp[i].q0;		f->curtext->q1 = rp[i].q1;		cmdexec(f->curtext, cp);	}}voidlooper(File *f, Cmd *cp, int xy){	long p, op, nrp;	Range r, tr;	Range *rp;	r = addr.r;	op= xy? -1 : r.q0;	nest++;	if(rxcompile(cp->re->r) == FALSE)		editerror("bad regexp in %c command", cp->cmdc);	nrp = 0;	rp = nil;	for(p = r.q0; p<=r.q1; ){		if(!rxexecute(f->curtext, nil, p, r.q1, &sel)){ /* no match, but y should still run */			if(xy || op>r.q1)				break;			tr.q0 = op, tr.q1 = r.q1;			p = r.q1+1;	/* exit next loop */		}else{			if(sel.r[0].q0==sel.r[0].q1){	/* empty match? */				if(sel.r[0].q0==op){					p++;					continue;				}				p = sel.r[0].q1+1;			}else				p = sel.r[0].q1;			if(xy)				tr = sel.r[0];			else				tr.q0 = op, tr.q1 = sel.r[0].q0;		}		op = sel.r[0].q1;		nrp++;		rp = erealloc(rp, nrp*sizeof(Range));		rp[nrp-1] = tr;	}	loopcmd(f, cp->cmd, rp, nrp);	free(rp);	--nest;}voidlinelooper(File *f, Cmd *cp){	long nrp, p;	Range r, linesel;	Address a, a3;	Range *rp;	nest++;	nrp = 0;	rp = nil;	r = addr.r;	a3.f = f;	a3.r.q0 = a3.r.q1 = r.q0;	a = lineaddr(0, a3, 1);	linesel = a.r;	for(p = r.q0; p<r.q1; p = a3.r.q1){		a3.r.q0 = a3.r.q1;		if(p!=r.q0 || linesel.q1==p){			a = lineaddr(1, a3, 1);			linesel = a.r;		}		if(linesel.q0 >= r.q1)			break;		if(linesel.q1 >= r.q1)			linesel.q1 = r.q1;		if(linesel.q1 > linesel.q0)			if(linesel.q0>=a3.r.q1 && linesel.q1>a3.r.q1){				a3.r = linesel;				nrp++;				rp = erealloc(rp, nrp*sizeof(Range));				rp[nrp-1] = linesel;				continue;			}		break;	}	loopcmd(f, cp->cmd, rp, nrp);	free(rp);	--nest;}struct Looper{	Cmd *cp;	int	XY;	Window	**w;	int	nw;} loopstruct;	/* only one; X and Y can't nest */voidalllooper(Window *w, void *v){	Text *t;	struct Looper *lp;	Cmd *cp;	lp = v;	cp = lp->cp;//	if(w->isscratch || w->isdir)//		return;	t = &w->body;	/* only use this window if it's the current window for the file */	if(t->file->curtext != t)		return;//	if(w->nopen[QWevent] > 0)//		return;	/* no auto-execute on files without names */	if(cp->re==nil && t->file->nname==0)		return;	if(cp->re==nil || filematch(t->file, cp->re)==lp->XY){		lp->w = erealloc(lp->w, (lp->nw+1)*sizeof(Window*));		lp->w[lp->nw++] = w;	}}voidalllocker(Window *w, void *v){	if(v)		incref(w);	else		winclose(w);}voidfilelooper(Cmd *cp, int XY){	int i;	if(Glooping++)		editerror("can't nest %c command", "YX"[XY]);	nest++;	loopstruct.cp = cp;	loopstruct.XY = XY;	if(loopstruct.w)	/* error'ed out last time */		free(loopstruct.w);	loopstruct.w = nil;	loopstruct.nw = 0;	allwindows(alllooper, &loopstruct);	/*	 * add a ref to all windows to keep safe windows accessed by X	 * that would not otherwise have a ref to hold them up during	 * the shenanigans.  note this with globalincref so that any	 * newly created windows start with an extra reference.	 */	allwindows(alllocker, (void*)1);	globalincref = 1;	for(i=0; i<loopstruct.nw; i++)		cmdexec(&loopstruct.w[i]->body, cp->cmd);	allwindows(alllocker, (void*)0);	globalincref = 0;	free(loopstruct.w);	loopstruct.w = nil;	--Glooping;	--nest;}voidnextmatch(File *f, String *r, long p, int sign){	if(rxcompile(r->r) == FALSE)		editerror("bad regexp in command address");	if(sign >= 0){		if(!rxexecute(f->curtext, nil, p, 0x7FFFFFFFL, &sel))			editerror("no match for regexp");		if(sel.r[0].q0==sel.r[0].q1 && sel.r[0].q0==p){			if(++p>f->nc)				p = 0;			if(!rxexecute(f->curtext, nil, p, 0x7FFFFFFFL, &sel))				editerror("address");		}	}else{		if(!rxbexecute(f->curtext, p, &sel))			editerror("no match for regexp");		if(sel.r[0].q0==sel.r[0].q1 && sel.r[0].q1==p){			if(--p<0)				p = f->nc;			if(!rxbexecute(f->curtext, p, &sel))				editerror("address");		}	}}File	*matchfile(String*);Address	charaddr(long, Address, int);Address	lineaddr(long, Address, int);Addresscmdaddress(Addr *ap, Address a, int sign){	File *f = a.f;	Address a1, a2;	do{		switch(ap->type){		case 'l':		case '#':			a = (*(ap->type=='#'?charaddr:lineaddr))(ap->num, a, sign);			break;		case '.':			mkaddr(&a, f);			break;		case '$':			a.r.q0 = a.r.q1 = f->nc;			break;		case '\'':editerror("can't handle '");//			a.r = f->mark;			break;		case '?':			sign = -sign;			if(sign == 0)				sign = -1;			/* fall through */		case '/':			nextmatch(f, ap->re, sign>=0? a.r.q1 : a.r.q0, sign);			a.r = sel.r[0];			break;		case '"':			f = matchfile(ap->re);			mkaddr(&a, f);			break;		case '*':			a.r.q0 = 0, a.r.q1 = f->nc;			return a;		case ',':		case ';':			if(ap->left)				a1 = cmdaddress(ap->left, a, 0);			else				a1.f = a.f, a1.r.q0 = a1.r.q1 = 0;			if(ap->type == ';'){				f = a1.f;				a = a1;				f->curtext->q0 = a1.r.q0;				f->curtext->q1 = a1.r.q1;			}			if(ap->next)				a2 = cmdaddress(ap->next, a, 0);			else				a2.f = a.f, a2.r.q0 = a2.r.q1 = f->nc;			if(a1.f != a2.f)				editerror("addresses in different files");			a.f = a1.f, a.r.q0 = a1.r.q0, a.r.q1 = a2.r.q1;			if(a.r.q1 < a.r.q0)				editerror("addresses out of order");			return a;		case '+':		case '-':			sign = 1;			if(ap->type == '-')				sign = -1;			if(ap->next==0 || ap->next->type=='+' || ap->next->type=='-')				a = lineaddr(1L, a, sign);			break;		default:			error("cmdaddress");			return a;		}	}while(ap = ap->next);	/* assign = */	return a;}struct Tofile{	File		*f;	String	*r;};voidalltofile(Window *w, void *v){	Text *t;	struct Tofile *tp;	tp = v;	if(tp->f != nil)		return;	if(w->isscratch || w->isdir)		return;	t = &w->body;	/* only use this window if it's the current window for the file */	if(t->file->curtext != t)		return;//	if(w->nopen[QWevent] > 0)//		return;	if(runeeq(tp->r->r, tp->r->n, t->file->name, t->file->nname))		tp->f = t->file;}File*tofile(String *r){	struct Tofile t;	String rr;	rr.r = skipbl(r->r, r->n, &rr.n);	t.f = nil;	t.r = &rr;	allwindows(alltofile, &t);	if(t.f == nil)		editerror("no such file\"%S\"", rr.r);	return t.f;}voidallmatchfile(Window *w, void *v){	struct Tofile *tp;	Text *t;	tp = v;	if(w->isscratch || w->isdir)		return;	t = &w->body;	/* only use this window if it's the current window for the file */	if(t->file->curtext != t)		return;//	if(w->nopen[QWevent] > 0)//		return;	if(filematch(w->body.file, tp->r)){		if(tp->f != nil)			editerror("too many files match \"%S\"", tp->r->r);		tp->f = w->body.file;	}}File*matchfile(String *r){	struct Tofile tf;	tf.f = nil;	tf.r = r;	allwindows(allmatchfile, &tf);	if(tf.f == nil)		editerror("no file matches \"%S\"", r->r);	return tf.f;}intfilematch(File *f, String *r){	char *buf;	Rune *rbuf;	Window *w;	int match, i, dirty;	Rangeset s;	/* compile expr first so if we get an error, we haven't allocated anything */	if(rxcompile(r->r) == FALSE)		editerror("bad regexp in file match");	buf = fbufalloc();	w = f->curtext->w;	/* same check for dirty as in settag, but we know ncache==0 */	dirty = !w->isdir && !w->isscratch && f->mod;	snprint(buf, BUFSIZE, "%c%c%c %.*S\n", " '"[dirty],		'+', " ."[curtext!=nil && curtext->file==f], f->nname, f->name);	rbuf = bytetorune(buf, &i);	fbuffree(buf);	match = rxexecute(nil, rbuf, 0, i, &s);	free(rbuf);	return match;}Addresscharaddr(long l, Address addr, int sign){	if(sign == 0)		addr.r.q0 = addr.r.q1 = l;	else if(sign < 0)		addr.r.q1 = addr.r.q0 -= l;	else if(sign > 0)		addr.r.q0 = addr.r.q1 += l;	if(addr.r.q0<0 || addr.r.q1>addr.f->nc)		editerror("address out of range");	return addr;}Addresslineaddr(long l, Address addr, int sign){	int n;	int c;	File *f = addr.f;	Address a;	long p;	a.f = f;	if(sign >= 0){		if(l == 0){			if(sign==0 || addr.r.q1==0){				a.r.q0 = a.r.q1 = 0;				return a;			}			a.r.q0 = addr.r.q1;			p = addr.r.q1-1;		}else{			if(sign==0 || addr.r.q1==0){				p = 0;				n = 1;			}else{				p = addr.r.q1-1;				n = textreadc(f->curtext, p++)=='\n';			}			while(n < l){				if(p >= f->nc)					editerror("address out of range");				if(textreadc(f->curtext, p++) == '\n')					n++;			}			a.r.q0 = p;		}		while(p < f->nc && textreadc(f->curtext, p++)!='\n')			;		a.r.q1 = p;	}else{		p = addr.r.q0;		if(l == 0)			a.r.q1 = addr.r.q0;		else{			for(n = 0; n<l; ){	/* always runs once */				if(p == 0){					if(++n != l)						editerror("address out of range");				}else{					c = textreadc(f->curtext, p-1);					if(c != '\n' || ++n != l)						p--;				}			}			a.r.q1 = p;			if(p > 0)				p--;		}		while(p > 0 && textreadc(f->curtext, p-1)!='\n')	/* lines start after a newline */			p--;		a.r.q0 = p;	}	return a;}struct Filecheck{	File	*f;	Rune	*r;	int nr;};voidallfilecheck(Window *w, void *v){	struct Filecheck *fp;	File *f;	fp = v;	f = w->body.file;	if(w->body.file == fp->f)		return;	if(runeeq(fp->r, fp->nr, f->name, f->nname))		warning(nil, "warning: duplicate file name \"%.*S\"\n", fp->nr, fp->r);}Rune*cmdname(File *f, String *str, int set){	Rune *r, *s;	int n;	struct Filecheck fc;	Runestr newname;	r = nil;	n = str->n;	s = str->r;	if(n == 0){		/* no name; use existing */		if(f->nname == 0)			return nil;		r = runemalloc(f->nname+1);		runemove(r, f->name, f->nname);		return r;	}	s = skipbl(s, n, &n);	if(n == 0)		goto Return;	if(s[0] == '/'){		r = runemalloc(n+1);		runemove(r, s, n);	}else{		newname = dirname(f->curtext, runestrdup(s), n);		n = newname.nr;		r = runemalloc(n+1);	/* NUL terminate */		runemove(r, newname.r, n);		free(newname.r);	}	fc.f = f;	fc.r = r;	fc.nr = n;	allwindows(allfilecheck, &fc);	if(f->nname == 0)		set = TRUE;    Return:	if(set && !runeeq(r, n, f->name, f->nname)){		filemark(f);		f->mod = TRUE;		f->curtext->w->dirty = TRUE;		winsetname(f->curtext->w, r, n);	}	return r;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -