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

📄 edit.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#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"static char	linex[]="\n";static char	wordx[]=" \t\n";struct cmdtab cmdtab[]={/*	cmdc	text	regexp	addr	defcmd	defaddr	count	token	 fn	*/	'\n',	0,	0,	0,	0,	aDot,	0,	0,	nl_cmd,	'a',	1,	0,	0,	0,	aDot,	0,	0,	a_cmd,	'b',	0,	0,	0,	0,	aNo,	0,	linex,	b_cmd,	'c',	1,	0,	0,	0,	aDot,	0,	0,	c_cmd,	'd',	0,	0,	0,	0,	aDot,	0,	0,	d_cmd,	'e',	0,	0,	0,	0,	aNo,	0,	wordx,	e_cmd,	'f',	0,	0,	0,	0,	aNo,	0,	wordx,	f_cmd,	'g',	0,	1,	0,	'p',	aDot,	0,	0,	g_cmd,	'i',	1,	0,	0,	0,	aDot,	0,	0,	i_cmd,	'm',	0,	0,	1,	0,	aDot,	0,	0,	m_cmd,	'p',	0,	0,	0,	0,	aDot,	0,	0,	p_cmd,	'r',	0,	0,	0,	0,	aDot,	0,	wordx,	e_cmd,	's',	0,	1,	0,	0,	aDot,	1,	0,	s_cmd,	't',	0,	0,	1,	0,	aDot,	0,	0,	m_cmd,	'u',	0,	0,	0,	0,	aNo,	2,	0,	u_cmd,	'v',	0,	1,	0,	'p',	aDot,	0,	0,	g_cmd,	'w',	0,	0,	0,	0,	aAll,	0,	wordx,	w_cmd,	'x',	0,	1,	0,	'p',	aDot,	0,	0,	x_cmd,	'y',	0,	1,	0,	'p',	aDot,	0,	0,	x_cmd,	'=',	0,	0,	0,	0,	aDot,	0,	linex,	eq_cmd,	'B',	0,	0,	0,	0,	aNo,	0,	linex,	B_cmd,	'D',	0,	0,	0,	0,	aNo,	0,	linex,	D_cmd,	'X',	0,	1,	0,	'f',	aNo,	0,	0,	X_cmd,	'Y',	0,	1,	0,	'f',	aNo,	0,	0,	X_cmd,	'<',	0,	0,	0,	0,	aDot,	0,	linex,	pipe_cmd,	'|',	0,	0,	0,	0,	aDot,	0,	linex,	pipe_cmd,	'>',	0,	0,	0,	0,	aDot,	0,	linex,	pipe_cmd,/* deliberately unimplemented:	'k',	0,	0,	0,	0,	aDot,	0,	0,	k_cmd,	'n',	0,	0,	0,	0,	aNo,	0,	0,	n_cmd,	'q',	0,	0,	0,	0,	aNo,	0,	0,	q_cmd,	'!',	0,	0,	0,	0,	aNo,	0,	linex,	plan9_cmd, */	0,	0,	0,	0,	0,	0,	0,	0,};Cmd	*parsecmd(int);Addr	*compoundaddr(void);Addr	*simpleaddr(void);void	freecmd(void);void	okdelim(int);Rune	*cmdstartp;Rune	*cmdendp;Rune	*cmdp;Channel	*editerrc;String	*lastpat;int	patset;List	cmdlist;List	addrlist;List	stringlist;Text	*curtext;int	editing = Inactive;String*	newstring(int);voideditthread(void*){	Cmd *cmdp;	threadsetname("editthread");	while((cmdp=parsecmd(0)) != 0){//		ocurfile = curfile;//		loaded = curfile && !curfile->unread;		if(cmdexec(curtext, cmdp) == 0)			break;		freecmd();	}	sendp(editerrc, nil);}voidallelogterm(Window *w, void*){	elogterm(w->body.file);}voidalleditinit(Window *w, void*){	textcommit(&w->tag, TRUE);	textcommit(&w->body, TRUE);	w->body.file->editclean = FALSE;}voidallupdate(Window *w, void*){	Text *t;	int i;	File *f;	t = &w->body;	f = t->file;	if(f->curtext != t)	/* do curtext only */		return;	if(f->elog.type == Null)		elogterm(f);	else if(f->elog.type != Empty){		elogapply(f);		if(f->editclean){			f->mod = FALSE;			for(i=0; i<f->ntext; i++)				f->text[i]->w->dirty = FALSE;		}	}	textsetselect(t, t->q0, t->q1);	textscrdraw(t);	winsettag(w);}voidediterror(char *fmt, ...){	va_list arg;	char *s;	va_start(arg, fmt);	s = vsmprint(fmt, arg);	va_end(arg);	freecmd();	allwindows(allelogterm, nil);	/* truncate the edit logs */	sendp(editerrc, s);	threadexits(nil);}voideditcmd(Text *ct, Rune *r, uint n){	char *err;	if(n == 0)		return;	if(2*n > RBUFSIZE){		warning(nil, "string too long\n");		return;	}	allwindows(alleditinit, nil);	if(cmdstartp)		free(cmdstartp);	cmdstartp = runemalloc(n+2);	runemove(cmdstartp, r, n);	if(r[n] != '\n')		cmdstartp[n++] = '\n';	cmdstartp[n] = '\0';	cmdendp = cmdstartp+n;	cmdp = cmdstartp;	if(ct->w == nil)		curtext = nil;	else		curtext = &ct->w->body;	resetxec();	if(editerrc == nil){		editerrc = chancreate(sizeof(char*), 0);		lastpat = allocstring(0);	}	threadcreate(editthread, nil, STACK);	err = recvp(editerrc);	editing = Inactive;	if(err != nil){		if(err[0] != '\0')			warning(nil, "Edit: %s\n", err);		free(err);	}	/* update everyone whose edit log has data */	allwindows(allupdate, nil);}intgetch(void){	if(*cmdp == *cmdendp)		return -1;	return *cmdp++;}intnextc(void){	if(*cmdp == *cmdendp)		return -1;	return *cmdp;}voidungetch(void){	if(--cmdp < cmdstartp)		error("ungetch");}longgetnum(int signok){	long n;	int c, sign;	n = 0;	sign = 1;	if(signok>1 && nextc()=='-'){		sign = -1;		getch();	}	if((c=nextc())<'0' || '9'<c)	/* no number defaults to 1 */		return sign;	while('0'<=(c=getch()) && c<='9')		n = n*10 + (c-'0');	ungetch();	return sign*n;}intcmdskipbl(void){	int c;	do		c = getch();	while(c==' ' || c=='\t');	if(c >= 0)		ungetch();	return c;}/* * Check that list has room for one more element. */voidgrowlist(List *l){	if(l->listptr==0 || l->nalloc==0){		l->nalloc = INCR;		l->listptr = emalloc(INCR*sizeof(void*));		l->nused = 0;	}else if(l->nused == l->nalloc){		l->listptr = erealloc(l->listptr, (l->nalloc+INCR)*sizeof(void*));		memset(l->ptr+l->nalloc, 0, INCR*sizeof(void*));		l->nalloc += INCR;	}}/* * Remove the ith element from the list */voiddellist(List *l, int i){	memmove(&l->ptr[i], &l->ptr[i+1], (l->nused-(i+1))*sizeof(void*));	l->nused--;}/* * Add a new element, whose position is i, to the list */voidinslist(List *l, int i, void *v){	growlist(l);	memmove(&l->ptr[i+1], &l->ptr[i], (l->nused-i)*sizeof(void*));	l->ptr[i] = v;	l->nused++;}voidlistfree(List *l){	free(l->listptr);	free(l);}String*allocstring(int n){	String *s;	s = emalloc(sizeof(String));	s->n = n;	s->nalloc = n+10;	s->r = emalloc(s->nalloc*sizeof(Rune));	s->r[n] = '\0';	return s;}voidfreestring(String *s){	free(s->r);	free(s);}Cmd*newcmd(void){	Cmd *p;	p = emalloc(sizeof(Cmd));	inslist(&cmdlist, cmdlist.nused, p);	return p;}String*newstring(int n){	String *p;	p = allocstring(n);	inslist(&stringlist, stringlist.nused, p);	return p;}Addr*newaddr(void){	Addr *p;	p = emalloc(sizeof(Addr));	inslist(&addrlist, addrlist.nused, p);	return p;}voidfreecmd(void){	int i;	while(cmdlist.nused > 0)		free(cmdlist.ucharptr[--cmdlist.nused]);	while(addrlist.nused > 0)		free(addrlist.ucharptr[--addrlist.nused]);	while(stringlist.nused>0){		i = --stringlist.nused;		freestring(stringlist.stringptr[i]);	}}voidokdelim(int c){	if(c=='\\' || ('a'<=c && c<='z')	|| ('A'<=c && c<='Z') || ('0'<=c && c<='9'))		editerror("bad delimiter %c\n", c);}voidatnl(void){	int c;	cmdskipbl();	c = getch();	if(c != '\n')		editerror("newline expected (saw %C)", c);}voidStraddc(String *s, int c){	if(s->n+1 >= s->nalloc){		s->nalloc += 10;		s->r = erealloc(s->r, s->nalloc*sizeof(Rune));	}	s->r[s->n++] = c;	s->r[s->n] = '\0';}voidgetrhs(String *s, int delim, int cmd){	int c;	while((c = getch())>0 && c!=delim && c!='\n'){		if(c == '\\'){			if((c=getch()) <= 0)				error("bad right hand side");			if(c == '\n'){				ungetch();				c='\\';			}else if(c == 'n')				c='\n';			else if(c!=delim && (cmd=='s' || c!='\\'))	/* s does its own */				Straddc(s, '\\');		}		Straddc(s, c);	}	ungetch();	/* let client read whether delimiter, '\n' or whatever */}String *collecttoken(char *end){	String *s = newstring(0);	int c;	while((c=nextc())==' ' || c=='\t')		Straddc(s, getch()); /* blanks significant for getname() */	while((c=getch())>0 && utfrune(end, c)==0)		Straddc(s, c);	if(c != '\n')		atnl();	return s;}String *collecttext(void){	String *s;	int begline, i, c, delim;	s = newstring(0);	if(cmdskipbl()=='\n'){		getch();		i = 0;		do{			begline = i;			while((c = getch())>0 && c!='\n')				i++, Straddc(s, c);			i++, Straddc(s, '\n');			if(c < 0)				goto Return;		}while(s->r[begline]!='.' || s->r[begline+1]!='\n');		s->r[s->n-2] = '\0';		s->n -= 2;	}else{		okdelim(delim = getch());		getrhs(s, delim, 'a');		if(nextc()==delim)			getch();		atnl();	}    Return:	return s;}intcmdlookup(int c){	int i;	for(i=0; cmdtab[i].cmdc; i++)		if(cmdtab[i].cmdc == c)			return i;	return -1;}Cmd*parsecmd(int nest){	int i, c;	struct cmdtab *ct;	Cmd *cp, *ncp;	Cmd cmd;	cmd.next = cmd.cmd = 0;	cmd.re = 0;	cmd.flag = cmd.num = 0;	cmd.addr = compoundaddr();	if(cmdskipbl() == -1)		return 0;	if((c=getch())==-1)		return 0;	cmd.cmdc = c;	if(cmd.cmdc=='c' && nextc()=='d'){	/* sleazy two-character case */		getch();		/* the 'd' */		cmd.cmdc='c'|0x100;	}	i = cmdlookup(cmd.cmdc);	if(i >= 0){		if(cmd.cmdc == '\n')			goto Return;	/* let nl_cmd work it all out */		ct = &cmdtab[i];		if(ct->defaddr==aNo && cmd.addr)			editerror("command takes no address");		if(ct->count)			cmd.num = getnum(ct->count);		if(ct->regexp){			/* x without pattern -> .*\n, indicated by cmd.re==0 */			/* X without pattern is all files */			if((ct->cmdc!='x' && ct->cmdc!='X') ||			   ((c = nextc())!=' ' && c!='\t' && c!='\n')){				cmdskipbl();				if((c = getch())=='\n' || c<0)					editerror("no address");				okdelim(c);				cmd.re = getregexp(c);				if(ct->cmdc == 's'){					cmd.text = newstring(0);					getrhs(cmd.text, c, 's');					if(nextc() == c){						getch();						if(nextc() == 'g')							cmd.flag = getch();					}							}			}		}		if(ct->addr && (cmd.mtaddr=simpleaddr())==0)			editerror("bad address");		if(ct->defcmd){			if(cmdskipbl() == '\n'){				getch();				cmd.cmd = newcmd();				cmd.cmd->cmdc = ct->defcmd;			}else if((cmd.cmd = parsecmd(nest))==0)				error("defcmd");		}else if(ct->text)			cmd.text = collecttext();		else if(ct->token)			cmd.text = collecttoken(ct->token);		else			atnl();	}else		switch(cmd.cmdc){		case '{':			cp = 0;			do{				if(cmdskipbl()=='\n')					getch();				ncp = parsecmd(nest+1);				if(cp)					cp->next = ncp;				else					cmd.cmd = ncp;			}while(cp = ncp);			break;		case '}':			atnl();			if(nest==0)				editerror("right brace with no left brace");			return 0;		default:			editerror("unknown command %c", cmd.cmdc);		}    Return:	cp = newcmd();	*cp = cmd;	return cp;}String*getregexp(int delim){	String *buf, *r;	int i, c;	buf = allocstring(0);	for(i=0; ; i++){		if((c = getch())=='\\'){			if(nextc()==delim)				c = getch();			else if(nextc()=='\\'){				Straddc(buf, c);				c = getch();			}		}else if(c==delim || c=='\n')			break;		if(i >= RBUFSIZE)			editerror("regular expression too long");		Straddc(buf, c);	}	if(c!=delim && c)		ungetch();	if(buf->n > 0){		patset = TRUE;		freestring(lastpat);		lastpat = buf;	}else		freestring(buf);	if(lastpat->n == 0)		editerror("no regular expression defined");	r = newstring(lastpat->n);	runemove(r->r, lastpat->r, lastpat->n);	/* newstring put \0 at end */	return r;}Addr *simpleaddr(void){	Addr addr;	Addr *ap, *nap;	addr.next = 0;	addr.left = 0;	switch(cmdskipbl()){	case '#':		addr.type = getch();		addr.num = getnum(1);		break;	case '0': case '1': case '2': case '3': case '4':	case '5': case '6': case '7': case '8': case '9': 		addr.num = getnum(1);		addr.type='l';		break;	case '/': case '?': case '"':		addr.re = getregexp(addr.type = getch());		break;	case '.':	case '$':	case '+':	case '-':	case '\'':		addr.type = getch();		break;	default:		return 0;	}	if(addr.next = simpleaddr())		switch(addr.next->type){		case '.':		case '$':		case '\'':			if(addr.type!='"')		case '"':				editerror("bad address syntax");			break;		case 'l':		case '#':			if(addr.type=='"')				break;			/* fall through */		case '/':		case '?':			if(addr.type!='+' && addr.type!='-'){				/* insert the missing '+' */				nap = newaddr();				nap->type='+';				nap->next = addr.next;				addr.next = nap;			}			break;		case '+':		case '-':			break;		default:			error("simpleaddr");		}	ap = newaddr();	*ap = addr;	return ap;}Addr *compoundaddr(void){	Addr addr;	Addr *ap, *next;	addr.left = simpleaddr();	if((addr.type = cmdskipbl())!=',' && addr.type!=';')		return addr.left;	getch();	next = addr.next = compoundaddr();	if(next && (next->type==',' || next->type==';') && next->left==0)		editerror("bad address syntax");	ap = newaddr();	*ap = addr;	return ap;}

⌨️ 快捷键说明

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