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

📄 ecmd.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <u.h>#include <libc.h>#include <draw.h>#include <thread.h>#include <cursor.h>#include <mouse.h>#include <keyboard.h>#include <frame.h>#include <fcall.h>#include <plumb.h>#include "dat.h"#include "edit.h"#include "fns.h"int	Glooping;int	nest;char	Enoname[] = "no file name given";Address	addr;File	*menu;Rangeset	sel;extern	Text*	curtext;Rune	*collection;int	ncollection;int	append(File*, Cmd*, long);int	pdisplay(File*);void	pfilename(File*);void	looper(File*, Cmd*, int);void	filelooper(Cmd*, int);void	linelooper(File*, Cmd*);Address	lineaddr(long, Address, int);int	filematch(File*, String*);File	*tofile(String*);Rune*	cmdname(File *f, String *s, int);void	runpipe(Text*, int, Rune*, int, int);voidclearcollection(void){	free(collection);	collection = nil;	ncollection = 0;}voidresetxec(void){	Glooping = nest = 0;	clearcollection();}voidmkaddr(Address *a, File *f){	a->r.q0 = f->curtext->q0;	a->r.q1 = f->curtext->q1;	a->f = f;}intcmdexec(Text *t, Cmd *cp){	int i;	Addr *ap;	File *f;	Window *w;	Address dot;	if(t == nil)		w = nil;	else		w = t->w;	if(w==nil && (cp->addr==0 || cp->addr->type!='"') &&	    !utfrune("bBnqUXY!", cp->cmdc) &&	    !(cp->cmdc=='D' && cp->text))		editerror("no current window");	i = cmdlookup(cp->cmdc);	/* will be -1 for '{' */	f = nil;	if(t && t->w){		t = &t->w->body;		f = t->file;		f->curtext = t;	}	if(i>=0 && cmdtab[i].defaddr != aNo){		if((ap=cp->addr)==0 && cp->cmdc!='\n'){			cp->addr = ap = newaddr();			ap->type = '.';			if(cmdtab[i].defaddr == aAll)				ap->type = '*';		}else if(ap && ap->type=='"' && ap->next==0 && cp->cmdc!='\n'){			ap->next = newaddr();			ap->next->type = '.';			if(cmdtab[i].defaddr == aAll)				ap->next->type = '*';		}		if(cp->addr){	/* may be false for '\n' (only) */			static Address none = {0,0,nil};			if(f){				mkaddr(&dot, f);				addr = cmdaddress(ap, dot, 0);			}else	/* a " */				addr = cmdaddress(ap, none, 0);			f = addr.f;			t = f->curtext;		}	}	switch(cp->cmdc){	case '{':		mkaddr(&dot, f);		if(cp->addr != nil)			dot = cmdaddress(cp->addr, dot, 0);		for(cp = cp->cmd; cp; cp = cp->next){			if(dot.r.q1 > t->file->nc)				editerror("dot extends past end of buffer during { command");			t->q0 = dot.r.q0;			t->q1 = dot.r.q1;			cmdexec(t, cp);		}		break;	default:		if(i < 0)			editerror("unknown command %c in cmdexec", cp->cmdc);		i = (*cmdtab[i].fn)(t, cp);		return i;	}	return 1;}char*edittext(Window *w, int q, Rune *r, int nr){	File *f;	f = w->body.file;	switch(editing){	case Inactive:		return "permission denied";	case Inserting:		eloginsert(f, q, r, nr);		return nil;	case Collecting:		collection = runerealloc(collection, ncollection+nr+1);		runemove(collection+ncollection, r, nr);		ncollection += nr;		collection[ncollection] = '\0';		return nil;	default:		return "unknown state in edittext";	}}/* string is known to be NUL-terminated */Rune*filelist(Text *t, Rune *r, int nr){	if(nr == 0)		return nil;	r = skipbl(r, nr, &nr);	if(r[0] != '<')		return runestrdup(r);	/* use < command to collect text */	clearcollection();	runpipe(t, '<', r+1, nr-1, Collecting);	return collection;}inta_cmd(Text *t, Cmd *cp){	return append(t->file, cp, addr.r.q1);}intb_cmd(Text*, Cmd *cp){	File *f;	f = tofile(cp->text);	if(nest == 0)		pfilename(f);	curtext = f->curtext;	return TRUE;}intB_cmd(Text *t, Cmd *cp){	Rune *list, *r, *s;	int nr;	list = filelist(t, cp->text->r, cp->text->n);	if(list == nil)		editerror(Enoname);	r = list;	nr = runestrlen(r);	r = skipbl(r, nr, &nr);	if(nr == 0)		new(t, t, nil, 0, 0, r, 0);	else while(nr > 0){		s = findbl(r, nr, &nr);		*s = '\0';		new(t, t, nil, 0, 0, r, runestrlen(r));		if(nr > 0)			r = skipbl(s+1, nr-1, &nr);	}	clearcollection();	return TRUE;}intc_cmd(Text *t, Cmd *cp){	elogreplace(t->file, addr.r.q0, addr.r.q1, cp->text->r, cp->text->n);	t->q0 = addr.r.q0;	t->q1 = addr.r.q0;	return TRUE;}intd_cmd(Text *t, Cmd*){	if(addr.r.q1 > addr.r.q0)		elogdelete(t->file, addr.r.q0, addr.r.q1);	t->q0 = addr.r.q0;	t->q1 = addr.r.q0;	return TRUE;}voidD1(Text *t){	if(t->w->body.file->ntext>1 || winclean(t->w, FALSE))		colclose(t->col, t->w, TRUE);}intD_cmd(Text *t, Cmd *cp){	Rune *list, *r, *s, *n;	int nr, nn;	Window *w;	Runestr dir, rs;	char buf[128];	list = filelist(t, cp->text->r, cp->text->n);	if(list == nil){		D1(t);		return TRUE;	}	dir = dirname(t, nil, 0);	r = list;	nr = runestrlen(r);	r = skipbl(r, nr, &nr);	do{		s = findbl(r, nr, &nr);		*s = '\0';		/* first time through, could be empty string, meaning delete file empty name */		nn = runestrlen(r);		if(r[0]=='/' || nn==0 || dir.nr==0){			rs.r = runestrdup(r);			rs.nr = nn;		}else{			n = runemalloc(dir.nr+1+nn);			runemove(n, dir.r, dir.nr);			n[dir.nr] = '/';			runemove(n+dir.nr+1, r, nn);			rs = cleanrname((Runestr){n, dir.nr+1+nn});		}		w = lookfile(rs.r, rs.nr);		if(w == nil){			snprint(buf, sizeof buf, "no such file %.*S", rs.nr, rs.r);			free(rs.r);			editerror(buf);		}		free(rs.r);		D1(&w->body);		if(nr > 0)			r = skipbl(s+1, nr-1, &nr);	}while(nr > 0);	clearcollection();	free(dir.r);	return TRUE;}static intreadloader(void *v, uint q0, Rune *r, int nr){	if(nr > 0)		eloginsert(v, q0, r, nr);	return 0;}inte_cmd(Text *t, Cmd *cp){	Rune *name;	File *f;	int i, isdir, q0, q1, fd, nulls, samename, allreplaced;	char *s, tmp[128];	Dir *d;	f = t->file;	q0 = addr.r.q0;	q1 = addr.r.q1;	if(cp->cmdc == 'e'){		if(winclean(t->w, TRUE)==FALSE)			editerror("");	/* winclean generated message already */		q0 = 0;		q1 = f->nc;	}	allreplaced = (q0==0 && q1==f->nc);	name = cmdname(f, cp->text, cp->cmdc=='e');	if(name == nil)		editerror(Enoname);	i = runestrlen(name);	samename = runeeq(name, i, t->file->name, t->file->nname);	s = runetobyte(name, i);	free(name);	fd = open(s, OREAD);	if(fd < 0){		snprint(tmp, sizeof tmp, "can't open %s: %r", s);		free(s);		editerror(tmp);	}	d = dirfstat(fd);	isdir = (d!=nil && (d->qid.type&QTDIR));	free(d);	if(isdir){		close(fd);		snprint(tmp, sizeof tmp, "%s is a directory", s);		free(s);		editerror(tmp);	}	elogdelete(f, q0, q1);	nulls = 0;	loadfile(fd, q1, &nulls, readloader, f);	free(s);	close(fd);	if(nulls)		warning(nil, "%s: NUL bytes elided\n", s);	else if(allreplaced && samename)		f->editclean = TRUE;	return TRUE;}intf_cmd(Text *t, Cmd *cp){	Rune *name;	String *str;	String empty;	if(cp->text == nil){		empty.n = 0;		empty.r = L"";		str = &empty;	}else		str = cp->text;	name = cmdname(t->file, str, TRUE);	free(name);	pfilename(t->file);	return TRUE;}intg_cmd(Text *t, Cmd *cp){	if(t->file != addr.f){		warning(nil, "internal error: g_cmd f!=addr.f\n");		return FALSE;	}	if(rxcompile(cp->re->r) == FALSE)		editerror("bad regexp in g command");	if(rxexecute(t, nil, addr.r.q0, addr.r.q1, &sel) ^ cp->cmdc=='v'){		t->q0 = addr.r.q0;		t->q1 = addr.r.q1;		return cmdexec(t, cp->cmd);	}	return TRUE;}inti_cmd(Text *t, Cmd *cp){	return append(t->file, cp, addr.r.q0);}voidcopy(File *f, Address addr2){	long p;	int ni;	Rune *buf;	buf = fbufalloc();	for(p=addr.r.q0; p<addr.r.q1; p+=ni){		ni = addr.r.q1-p;		if(ni > RBUFSIZE)			ni = RBUFSIZE;		bufread(f, p, buf, ni);		eloginsert(addr2.f, addr2.r.q1, buf, ni);	}	fbuffree(buf);}voidmove(File *f, Address addr2){	if(addr.f!=addr2.f || addr.r.q1<=addr2.r.q0){		elogdelete(f, addr.r.q0, addr.r.q1);		copy(f, addr2);	}else if(addr.r.q0 >= addr2.r.q1){		copy(f, addr2);		elogdelete(f, addr.r.q0, addr.r.q1);	}else		error("move overlaps itself");}intm_cmd(Text *t, Cmd *cp){	Address dot, addr2;	mkaddr(&dot, t->file);	addr2 = cmdaddress(cp->mtaddr, dot, 0);	if(cp->cmdc == 'm')		move(t->file, addr2);	else		copy(t->file, addr2);	return TRUE;}intp_cmd(Text *t, Cmd*){	return pdisplay(t->file);}ints_cmd(Text *t, Cmd *cp){	int i, j, k, c, m, n, nrp, didsub;	long p1, op, delta;	String *buf;	Rangeset *rp;	char *err;	Rune *rbuf;	n = cp->num;	op= -1;	if(rxcompile(cp->re->r) == FALSE)		editerror("bad regexp in s command");	nrp = 0;	rp = nil;	delta = 0;	didsub = FALSE;	for(p1 = addr.r.q0; p1<=addr.r.q1 && rxexecute(t, nil, p1, addr.r.q1, &sel); ){		if(sel.r[0].q0 == sel.r[0].q1){	/* empty match? */			if(sel.r[0].q0 == op){				p1++;				continue;			}			p1 = sel.r[0].q1+1;		}else			p1 = sel.r[0].q1;		op = sel.r[0].q1;		if(--n>0)			continue;		nrp++;		rp = erealloc(rp, nrp*sizeof(Rangeset));		rp[nrp-1] = sel;	}	rbuf = fbufalloc();	buf = allocstring(0);	for(m=0; m<nrp; m++){		buf->n = 0;		buf->r[0] = L'\0';		sel = rp[m];		for(i = 0; i<cp->text->n; i++)			if((c = cp->text->r[i])=='\\' && i<cp->text->n-1){				c = cp->text->r[++i];				if('1'<=c && c<='9') {					j = c-'0';					if(sel.r[j].q1-sel.r[j].q0>RBUFSIZE){						err = "replacement string too long";						goto Err;					}					bufread(t->file, sel.r[j].q0, rbuf, sel.r[j].q1-sel.r[j].q0);					for(k=0; k<sel.r[j].q1-sel.r[j].q0; k++)						Straddc(buf, rbuf[k]);				}else				 	Straddc(buf, c);			}else if(c!='&')				Straddc(buf, c);			else{				if(sel.r[0].q1-sel.r[0].q0>RBUFSIZE){					err = "right hand side too long in substitution";					goto Err;				}				bufread(t->file, sel.r[0].q0, rbuf, sel.r[0].q1-sel.r[0].q0);				for(k=0; k<sel.r[0].q1-sel.r[0].q0; k++)					Straddc(buf, rbuf[k]);			}		elogreplace(t->file, sel.r[0].q0, sel.r[0].q1,  buf->r, buf->n);		delta -= sel.r[0].q1-sel.r[0].q0;		delta += buf->n;		didsub = 1;		if(!cp->flag)			break;	}	free(rp);	freestring(buf);	fbuffree(rbuf);	if(!didsub && nest==0)		editerror("no substitution");	t->q0 = addr.r.q0;	t->q1 = addr.r.q1;	return TRUE;Err:	free(rp);	freestring(buf);	fbuffree(rbuf);	editerror(err);	return FALSE;}intu_cmd(Text *t, Cmd *cp){	int n, oseq, flag;	n = cp->num;	flag = TRUE;	if(n < 0){		n = -n;		flag = FALSE;	}	oseq = -1;	while(n-->0 && t->file->seq!=0 && t->file->seq!=oseq){		oseq = t->file->seq;		undo(t, nil, nil, flag, 0, nil, 0);	}	return TRUE;}intw_cmd(Text *t, Cmd *cp){	Rune *r;	File *f;	f = t->file;	if(f->seq == seq)		editerror("can't write file with pending modifications");	r = cmdname(f, cp->text, FALSE);	if(r == nil)		editerror("no name specified for 'w' command");	putfile(f, addr.r.q0, addr.r.q1, r, runestrlen(r));	/* r is freed by putfile */	return TRUE;}intx_cmd(Text *t, Cmd *cp){	if(cp->re)		looper(t->file, cp, cp->cmdc=='x');	else		linelooper(t->file, cp);	return TRUE;}intX_cmd(Text*, Cmd *cp){	filelooper(cp, cp->cmdc=='X');	return TRUE;}voidrunpipe(Text *t, int cmd, Rune *cr, int ncr, int state){	Rune *r, *s;	int n;	Runestr dir;	Window *w;	r = skipbl(cr, ncr, &n);	if(n == 0)		editerror("no command specified for %c", cmd);	w = nil;	if(state == Inserting){		w = t->w;		t->q0 = addr.r.q0;		t->q1 = addr.r.q1;		if(cmd == '<' || cmd=='|')			elogdelete(t->file, t->q0, t->q1);	}	s = runemalloc(n+2);	s[0] = cmd;	runemove(s+1, r, n);	n++;	dir.r = nil;	dir.nr = 0;	if(t != nil)		dir = dirname(t, nil, 0);	if(dir.nr==1 && dir.r[0]=='.'){	/* sigh */		free(dir.r);		dir.r = nil;		dir.nr = 0;	}	editing = state;	if(t!=nil && t->w!=nil)		incref(t->w);	/* run will decref */	run(w, runetobyte(s, n), dir.r, dir.nr, TRUE, nil, nil, TRUE);	free(s);	if(t!=nil && t->w!=nil)		winunlock(t->w);	qunlock(&row);	recvul(cedit);	qlock(&row);	editing = Inactive;	if(t!=nil && t->w!=nil)		winlock(t->w, 'M');}intpipe_cmd(Text *t, Cmd *cp){	runpipe(t, cp->cmdc, cp->text->r, cp->text->n, Inserting);	return TRUE;}longnlcount(Text *t, long q0, long q1){	long nl;	Rune *buf;	int i, nbuf;	buf = fbufalloc();	nbuf = 0;	i = nl = 0;	while(q0 < q1){		if(i == nbuf){			nbuf = q1-q0;			if(nbuf > RBUFSIZE)				nbuf = RBUFSIZE;			bufread(t->file, q0, buf, nbuf);			i = 0;		}		if(buf[i++] == '\n')			nl++;		q0++;	}	fbuffree(buf);	return nl;}

⌨️ 快捷键说明

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