1455 lines · 29.2 KB · C
RawDownload
#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 "fns.h" Buffer	snarfbuf; /* * These functions get called as: * *	fn(et, t, argt, flag1, flag1, flag2, s, n); * * Where the arguments are: * *	et: the Text* in which the executing event (click) occurred *	t: the Text* containing the current selection (Edit, Cut, Snarf, Paste) *	argt: the Text* containing the argument for a 2-1 click. *	e->flag1: from Exectab entry * 	e->flag2: from Exectab entry *	s: the command line remainder (e.g., "x" if executing "Dump x") *	n: length of s  (s is *not* NUL-terminated) */ void	del(Text*, Text*, Text*, int, int, Rune*, int);void	delcol(Text*, Text*, Text*, int, int, Rune*, int);void	dump(Text*, Text*, Text*, int, int, Rune*, int);void	edit(Text*, Text*, Text*, int, int, Rune*, int);void	exit(Text*, Text*, Text*, int, int, Rune*, int);void	fontx(Text*, Text*, Text*, int, int, Rune*, int);void	get(Text*, Text*, Text*, int, int, Rune*, int);void	id(Text*, Text*, Text*, int, int, Rune*, int);void	incl(Text*, Text*, Text*, int, int, Rune*, int);void	indent(Text*, Text*, Text*, int, int, Rune*, int);void	kill(Text*, Text*, Text*, int, int, Rune*, int);void	local(Text*, Text*, Text*, int, int, Rune*, int);void	look(Text*, Text*, Text*, int, int, Rune*, int);void	newcol(Text*, Text*, Text*, int, int, Rune*, int);void	paste(Text*, Text*, Text*, int, int, Rune*, int);void	put(Text*, Text*, Text*, int, int, Rune*, int);void	putall(Text*, Text*, Text*, int, int, Rune*, int);void	sendx(Text*, Text*, Text*, int, int, Rune*, int);void	sort(Text*, Text*, Text*, int, int, Rune*, int);void	tab(Text*, Text*, Text*, int, int, Rune*, int);void	zeroxx(Text*, Text*, Text*, int, int, Rune*, int); typedef struct Exectab Exectab;struct Exectab{	Rune	*name;	void	(*fn)(Text*, Text*, Text*, int, int, Rune*, int);	int		mark;	int		flag1;	int		flag2;}; Exectab exectab[] = {	{ L"Cut",		cut,		TRUE,	TRUE,	TRUE	},	{ L"Del",		del,		FALSE,	FALSE,	XXX		},	{ L"Delcol",	delcol,	FALSE,	XXX,		XXX		},	{ L"Delete",	del,		FALSE,	TRUE,	XXX		},	{ L"Dump",	dump,	FALSE,	TRUE,	XXX		},	{ L"Edit",		edit,		FALSE,	XXX,		XXX		},	{ L"Exit",		exit,		FALSE,	XXX,		XXX		},	{ L"Font",		fontx,	FALSE,	XXX,		XXX		},	{ L"Get",		get,		FALSE,	TRUE,	XXX		},	{ L"ID",		id,		FALSE,	XXX,		XXX		},	{ L"Incl",		incl,		FALSE,	XXX,		XXX		},	{ L"Indent",	indent,	FALSE,	XXX,		XXX		},	{ L"Kill",		kill,		FALSE,	XXX,		XXX		},	{ L"Load",		dump,	FALSE,	FALSE,	XXX		},	{ L"Local",		local,	FALSE,	XXX,		XXX		},	{ L"Look",		look,		FALSE,	XXX,		XXX		},	{ L"New",		new,		FALSE,	XXX,		XXX		},	{ L"Newcol",	newcol,	FALSE,	XXX,		XXX		},	{ L"Paste",		paste,	TRUE,	TRUE,	XXX		},	{ L"Put",		put,		FALSE,	XXX,		XXX		},	{ L"Putall",		putall,	FALSE,	XXX,		XXX		},	{ L"Redo",		undo,	FALSE,	FALSE,	XXX		},	{ L"Send",		sendx,	TRUE,	XXX,		XXX		},	{ L"Snarf",		cut,		FALSE,	TRUE,	FALSE	},	{ L"Sort",		sort,		FALSE,	XXX,		XXX		},	{ L"Tab",		tab,		FALSE,	XXX,		XXX		},	{ L"Undo",		undo,	FALSE,	TRUE,	XXX		},	{ L"Zerox",	zeroxx,	FALSE,	XXX,		XXX		},	{ nil, 			nil,		0,		0,		0		},}; Exectab*lookup(Rune *r, int n){	Exectab *e;	int nr; 	r = skipbl(r, n, &n);	if(n == 0)		return nil;	findbl(r, n, &nr);	nr = n-nr;	for(e=exectab; e->name; e++)		if(runeeq(r, nr, e->name, runestrlen(e->name)) == TRUE)			return e;	return nil;} intisexecc(int c){	if(isfilec(c))		return 1;	return c=='<' || c=='|' || c=='>';} voidexecute(Text *t, uint aq0, uint aq1, int external, Text *argt){	uint q0, q1;	Rune *r, *s;	char *b, *a, *aa;	Exectab *e;	int c, n, f;	Runestr dir; 	q0 = aq0;	q1 = aq1;	if(q1 == q0){	/* expand to find word (actually file name) */		/* if in selection, choose selection */		if(t->q1>t->q0 && t->q0<=q0 && q0<=t->q1){			q0 = t->q0;			q1 = t->q1;		}else{			while(q1<t->file->nc && isexecc(c=textreadc(t, q1)) && c!=':')				q1++;			while(q0>0 && isexecc(c=textreadc(t, q0-1)) && c!=':')				q0--;			if(q1 == q0)				return;		}	}	r = runemalloc(q1-q0);	bufread(t->file, q0, r, q1-q0);	e = lookup(r, q1-q0);	if(!external && t->w!=nil && t->w->nopen[QWevent]>0){		f = 0;		if(e)			f |= 1;		if(q0!=aq0 || q1!=aq1){			bufread(t->file, aq0, r, aq1-aq0);			f |= 2;		}		aa = getbytearg(argt, TRUE, TRUE, &a);		if(a){				if(strlen(a) > EVENTSIZE){	/* too big; too bad */				free(aa);				free(a);				warning(nil, "`argument string too long\n");				return;			}			f |= 8;		}		c = 'x';		if(t->what == Body)			c = 'X';		n = aq1-aq0;		if(n <= EVENTSIZE)			winevent(t->w, "%c%d %d %d %d %.*S\n", c, aq0, aq1, f, n, n, r);		else			winevent(t->w, "%c%d %d %d 0 \n", c, aq0, aq1, f, n);		if(q0!=aq0 || q1!=aq1){			n = q1-q0;			bufread(t->file, q0, r, n);			if(n <= EVENTSIZE)				winevent(t->w, "%c%d %d 0 %d %.*S\n", c, q0, q1, n, n, r);			else				winevent(t->w, "%c%d %d 0 0 \n", c, q0, q1, n);		}		if(a){			winevent(t->w, "%c0 0 0 %d %s\n", c, utflen(a), a);			if(aa)				winevent(t->w, "%c0 0 0 %d %s\n", c, utflen(aa), aa);			else				winevent(t->w, "%c0 0 0 0 \n", c);		}		free(r);		free(aa);		free(a);		return;	}	if(e){		if(e->mark && seltext!=nil)		if(seltext->what == Body){			seq++;			filemark(seltext->w->body.file);		}		s = skipbl(r, q1-q0, &n);		s = findbl(s, n, &n);		s = skipbl(s, n, &n);		(*e->fn)(t, seltext, argt, e->flag1, e->flag2, s, n);		free(r);		return;	} 	b = runetobyte(r, q1-q0);	free(r);	dir = dirname(t, nil, 0);	if(dir.nr==1 && dir.r[0]=='.'){	/* sigh */		free(dir.r);		dir.r = nil;		dir.nr = 0;	}	aa = getbytearg(argt, TRUE, TRUE, &a);	if(t->w)		incref(t->w);	run(t->w, b, dir.r, dir.nr, TRUE, aa, a, FALSE);} char*printarg(Text *argt, uint q0, uint q1){	char *buf; 	if(argt->what!=Body || argt->file->name==nil)		return nil;	buf = emalloc(argt->file->nname+32);	if(q0 == q1)		sprint(buf, "%.*S:#%d", argt->file->nname, argt->file->name, q0);	else		sprint(buf, "%.*S:#%d,#%d", argt->file->nname, argt->file->name, q0, q1);	return buf;} char*getarg(Text *argt, int doaddr, int dofile, Rune **rp, int *nrp){	int n;	Expand e;	char *a; 	*rp = nil;	*nrp = 0;	if(argt == nil)		return nil;	a = nil;	textcommit(argt, TRUE);	if(expand(argt, argt->q0, argt->q1, &e)){		free(e.bname);		if(e.nname && dofile){			e.name = runerealloc(e.name, e.nname+1);			if(doaddr)				a = printarg(argt, e.q0, e.q1);			*rp = e.name;			*nrp = e.nname;			return a;		}		free(e.name);	}else{		e.q0 = argt->q0;		e.q1 = argt->q1;	}	n = e.q1 - e.q0;	*rp = runemalloc(n+1);	bufread(argt->file, e.q0, *rp, n);	if(doaddr)		a = printarg(argt, e.q0, e.q1);	*nrp = n;	return a;} char*getbytearg(Text *argt, int doaddr, int dofile, char **bp){	Rune *r;	int n;	char *aa; 	*bp = nil;	aa = getarg(argt, doaddr, dofile, &r, &n);	if(r == nil)		return nil;	*bp = runetobyte(r, n);	free(r);	return aa;} voidnewcol(Text *et, Text*, Text*, int, int, Rune*, int){	Column *c; 	c = rowadd(et->row, nil, -1);	if(c)		winsettag(coladd(c, nil, nil, -1));} voiddelcol(Text *et, Text*, Text*, int, int, Rune*, int){	int i;	Column *c;	Window *w; 	c = et->col;	if(c==nil || colclean(c)==0)		return;	for(i=0; i<c->nw; i++){		w = c->w[i];		if(w->nopen[QWevent]+w->nopen[QWaddr]+w->nopen[QWdata]+w->nopen[QWxdata] > 0){			warning(nil, "can't delete column; %.*S is running an external command\n", w->body.file->nname, w->body.file->name);			return;		}	}	rowclose(et->col->row, et->col, TRUE);} voiddel(Text *et, Text*, Text *argt, int flag1, int, Rune *arg, int narg){	Window *w;	char *name, *p;	Plumbmsg *pm; 	if(et->col==nil || et->w == nil)		return;	if(flag1 || et->w->body.file->ntext>1 || winclean(et->w, FALSE)){		w = et->w;		name = getname(&w->body, argt, arg, narg, TRUE);		if(name && plumbsendfd >= 0){			pm = emalloc(sizeof(Plumbmsg));			pm->src = estrdup("acme");			pm->dst = estrdup("close");			pm->wdir = estrdup(name);			if(p = strrchr(pm->wdir, '/'))				*p = '\0';			pm->type = estrdup("text");			pm->attr = nil;			pm->data = estrdup(name);			pm->ndata = strlen(pm->data);			if(pm->ndata < messagesize-1024)				plumbsend(plumbsendfd, pm);			else				plumbfree(pm);		}		colclose(et->col, et->w, TRUE);	}} voidsort(Text *et, Text*, Text*, int, int, Rune*, int){	if(et->col)		colsort(et->col);} uintseqof(Window *w, int isundo){	/* if it's undo, see who changed with us */	if(isundo)		return w->body.file->seq;	/* if it's redo, see who we'll be sync'ed up with */	return fileredoseq(w->body.file);} voidundo(Text *et, Text*, Text*, int flag1, int, Rune*, int){	int i, j;	Column *c;	Window *w;	uint seq; 	if(et==nil || et->w== nil)		return;	seq = seqof(et->w, flag1);	if(seq == 0){		/* nothing to undo */		return;	}	/*	 * Undo the executing window first. Its display will update. other windows	 * in the same file will not call show() and jump to a different location in the file.	 * Simultaneous changes to other files will be chaotic, however.	 */	winundo(et->w, flag1);	for(i=0; i<row.ncol; i++){		c = row.col[i];		for(j=0; j<c->nw; j++){			w = c->w[j];			if(w == et->w)				continue;			if(seqof(w, flag1) == seq)				winundo(w, flag1);		}	}} char*getname(Text *t, Text *argt, Rune *arg, int narg, int isput){	char *s;	Rune *r;	int i, n, promote;	Runestr dir; 	getarg(argt, FALSE, TRUE, &r, &n);	promote = FALSE;	if(r == nil)		promote = TRUE;	else if(isput){		/* if are doing a Put, want to synthesize name even for non-existent file */		/* best guess is that file name doesn't contain a slash */		promote = TRUE;		for(i=0; i<n; i++)			if(r[i] == '/'){				promote = FALSE;				break;			}		if(promote){			t = argt;			arg = r;			narg = n;		}	}	if(promote){		n = narg;		if(n <= 0){			s = runetobyte(t->file->name, t->file->nname);			return s;		}		/* prefix with directory name if necessary */		dir.r = nil;		dir.nr = 0;		if(n>0 && arg[0]!='/'){			dir = dirname(t, nil, 0);			if(dir.nr==1 && dir.r[0]=='.'){	/* sigh */				free(dir.r);				dir.r = nil;				dir.nr = 0;			}		}		if(dir.r){			r = runemalloc(dir.nr+n+1);			runemove(r, dir.r, dir.nr);			free(dir.r);			if(dir.nr>0 && r[dir.nr]!='/' && n>0 && arg[0]!='/')				r[dir.nr++] = '/';			runemove(r+dir.nr, arg, n);			n += dir.nr;		}else{			r = runemalloc(n+1);			runemove(r, arg, n);		}	}	s = runetobyte(r, n);	free(r);	if(strlen(s) == 0){		free(s);		s = nil;	}	return s;} voidzeroxx(Text *et, Text *t, Text*, int, int, Rune*, int){	Window *nw;	int c, locked; 	locked = FALSE;	if(t!=nil && t->w!=nil && t->w!=et->w){		locked = TRUE;		c = 'M';		if(et->w)			c = et->w->owner;		winlock(t->w, c);	}	if(t == nil)		t = et;	if(t==nil || t->w==nil)		return;	t = &t->w->body;	if(t->w->isdir)		warning(nil, "%.*S is a directory; Zerox illegal\n", t->file->nname, t->file->name);	else{		nw = coladd(t->w->col, nil, t->w, -1);		/* ugly: fix locks so w->unlock works */		winlock1(nw, t->w->owner);	}	if(locked)		winunlock(t->w);} void

Lines 1–500 of 1455.