Charles.Forsyth20060303a828770d19 years agoHistory
1029 lines · 18.6 KB · C
RawDownload
#include "lib9.h"#include "draw.h"#include "tk.h"#include "textw.h" #define istring u.string#define iwin u.win#define imark u.mark#define iline u.line static char* tkttagadd(Tk*, char*, char**);static char* tkttagbind(Tk*, char*, char**);static char* tkttagcget(Tk*, char*, char**);static char* tkttagconfigure(Tk*, char*, char**);static char* tkttagdelete(Tk*, char*, char**);static char* tkttaglower(Tk*, char*, char**);static char* tkttagnames(Tk*, char*, char**);static char* tkttagnextrange(Tk*, char*, char**);static char* tkttagprevrange(Tk*, char*, char**);static char* tkttagraise(Tk*, char*, char**);static char* tkttagranges(Tk*, char*, char**);static char* tkttagremove(Tk*, char*, char**); #define	O(t, e)		((long)(&((t*)0)->e)) #define TKTEO		(O(TkTtaginfo, env))static TkOption tagopts[] ={	"borderwidth",		OPTnndist, O(TkTtaginfo, opts[TkTborderwidth]),	nil,	"justify",		OPTstab, O(TkTtaginfo, opts[TkTjustify]),	tkjustify,	"lineheight",		OPTnndist, O(TkTtaginfo, opts[TkTlineheight]),	IAUX(TKTEO),	"lmargin1",		OPTdist, O(TkTtaginfo, opts[TkTlmargin1]),	IAUX(TKTEO),	"lmargin2",		OPTdist, O(TkTtaginfo, opts[TkTlmargin2]),	IAUX(TKTEO),	"lmargin3",		OPTdist, O(TkTtaginfo, opts[TkTlmargin3]),	IAUX(TKTEO),	"rmargin",		OPTdist, O(TkTtaginfo, opts[TkTrmargin]),	IAUX(TKTEO),	"spacing1",		OPTnndist, O(TkTtaginfo, opts[TkTspacing1]),	IAUX(TKTEO),	"spacing2",		OPTnndist, O(TkTtaginfo, opts[TkTspacing2]),	IAUX(TKTEO),	"spacing3",		OPTnndist, O(TkTtaginfo, opts[TkTspacing3]),	IAUX(TKTEO),	"offset",			OPTdist, O(TkTtaginfo, opts[TkToffset]),	IAUX(TKTEO),	"underline",		OPTstab, O(TkTtaginfo, opts[TkTunderline]),	tkbool,	"overstrike",		OPTstab, O(TkTtaginfo, opts[TkToverstrike]),	tkbool,	"relief",		OPTstab, O(TkTtaginfo, opts[TkTrelief]),	tkrelief,	"tabs",			OPTtabs, O(TkTtaginfo, tabs),			IAUX(TKTEO),	"wrap",		OPTstab, O(TkTtaginfo, opts[TkTwrap]),		tkwrap,	nil,}; static TkOption tagenvopts[] ={	"foreground",	OPTcolr,	O(TkTtaginfo, env),	IAUX(TkCforegnd),	"background",	OPTcolr,	O(TkTtaginfo, env),	IAUX(TkCbackgnd),	"fg",		OPTcolr,	O(TkTtaginfo, env),	IAUX(TkCforegnd),	"bg",		OPTcolr,	O(TkTtaginfo, env),	IAUX(TkCbackgnd),	"font",		OPTfont,	O(TkTtaginfo, env),	nil,	nil}; TkCmdtabtkttagcmd[] ={	"add",		tkttagadd,	"bind",		tkttagbind,	"cget",		tkttagcget,	"configure",	tkttagconfigure,	"delete",	tkttagdelete,	"lower",	tkttaglower,	"names",	tkttagnames,	"nextrange",	tkttagnextrange,	"prevrange",	tkttagprevrange,	"raise",	tkttagraise,	"ranges",	tkttagranges,	"remove",	tkttagremove,	nil}; inttktanytags(TkTitem *it){	int i; 	if(it->tagextra == 0)		return (it->tags[0] != 0);	for(i = 0; i <= it->tagextra; i++)		if(it->tags[i] != 0)			return 1;	return 0;} inttktsametags(TkTitem *i1, TkTitem *i2){	int i, j; 	for(i = 0; i <= i1->tagextra && i <= i2->tagextra; i++)		if(i1->tags[i] != i2->tags[i])			return 0;	for(j = i; j <= i1->tagextra; j++)		if(i1->tags[j] != 0)			return 0;	for(j = i; j <= i2->tagextra; j++)		if(i2->tags[j] != 0)			return 0;	return 1;} inttkttagset(TkTitem *it, int id){	int i; 	if(it->tagextra == 0 && it->tags[0] == 0)		return 0;	for(i = 0; i <= it->tagextra; i++) {		if(id < 32)			return ((it->tags[i] & (1<<id)) != 0);		id -= 32;	}	return 0;} char *tkttagname(TkText *tkt, int id){	TkTtaginfo *t; 	for(t = tkt->tags; t != nil; t = t->next) {		if(t->id == id)			return t->name;	}	return "";} /* return 1 if this actually changes the value */inttkttagbit(TkTitem *it, int id, int val){	int i, changed;	ulong z, b; 	changed = 0;	for(i = 0; i <= it->tagextra; i++) {		if(id < 32) {			b = (1<<id);			z = it->tags[i];			if(val == 0) {				if(z & b) {					changed = 1;					it->tags[i] = z & (~b);				}			}			else {				if((z & b) == 0) {					changed = 1;					it->tags[i] = z | b;				}			}			break;		}		id -= 32;	}	return changed;} voidtkttagcomb(TkTitem *i1, TkTitem *i2, int add){	int i; 	for(i = 0; i <= i1->tagextra && i <= i2->tagextra; i++) {		if(add == 1)			i1->tags[i] |= i2->tags[i];		else if(add == 0)			/* intersect */			i1->tags[i] &= i2->tags[i];		else			/* subtract */			i1->tags[i] &= ~i2->tags[i];	}} char*tktaddtaginfo(Tk *tk, char *name, TkTtaginfo **ret){	int i, *ntagp;	TkTtaginfo *ti;	TkText *tkt, *tktshare; 	tkt = TKobj(TkText, tk);	ti = malloc(sizeof(TkTtaginfo));	if(ti == nil)		return TkNomem; 	ntagp = &tkt->nexttag;	if(tkt->tagshare != nil) {		tktshare = TKobj(TkText, tkt->tagshare);		ntagp = &tktshare->nexttag;	}	ti->id = *ntagp;	ti->name = strdup(name);	if(ti->name == nil) {		free(ti);		return TkNomem;	}	ti->env = tknewenv(tk->env->top);	if(ti->env == nil) {		free(ti->name);		free(ti);		return TkNomem;	} 	ti->tabs = nil;	for(i = 0; i < TkTnumopts; i++)		ti->opts[i] = TkTunset;	ti->next = tkt->tags;	tkt->tags = ti; 	(*ntagp)++;	if(tkt->tagshare)		tkt->nexttag = *ntagp; 	*ret = ti;	return nil;} TkTtaginfo *tktfindtag(TkTtaginfo *t, char *name){	while(t != nil) {		if(strcmp(t->name, name) == 0)			return t;		t = t->next;	}	return nil;} voidtktfreetags(TkTtaginfo *t){	TkTtaginfo *n; 	while(t != nil) {		n = t->next;		free(t->name);		tktfreetabs(t->tabs);		tkputenv(t->env);		tkfreebind(t->binds);		free(t);		t = n;	}} inttkttagind(Tk *tk, char *name, int first, TkTindex *ans){	int id;	TkTtaginfo *t;	TkText *tkt; 	tkt = TKobj(TkText, tk); 	if(strcmp(name, "sel") == 0) {		if(tkt->selfirst == nil)			return 0;		if(first)			tktitemind(tkt->selfirst, ans);		else			tktitemind(tkt->sellast, ans);		return 1;	} 	t = tktfindtag(tkt->tags, name);	if(t == nil)		return 0;	id = t->id; 	if(first) {		tktstartind(tkt, ans);		while(!tkttagset(ans->item, id))			if(!tktadjustind(tkt, TkTbyitem, ans))				return 0;	}	else {		tktendind(tkt, ans);		while(!tkttagset(ans->item, id))			if(!tktadjustind(tkt, TkTbyitemback, ans))				return 0;		tktadjustind(tkt, TkTbyitem, ans);	} 	return 1;} /* * Fill in opts and e, based on info from tags set in it, * using tags order for priority. * If dflt != 0, options not set are filled from tk, * otherwise iInteger options not set by any tag are left 'TkTunset' * and environment values not set are left nil. */voidtkttagopts(Tk *tk, TkTitem *it, int *opts, TkEnv *e, TkTtabstop **tb, int dflt){	int i;	int colset;	TkEnv *te;	TkTtaginfo *tags;	TkText *tkt = TKobj(TkText, tk); 	if (tb != nil)		*tb = tkt->tabs; 	tags = tkt->tags; 	if(opts != nil)		for(i = 0; i < TkTnumopts; i++)			opts[i] = TkTunset; 	memset(e, 0, sizeof(TkEnv));	e->top = tk->env->top;	colset = 0;	while(tags != nil) {		if(tkttagset(it, tags->id)) {			if(opts != nil) {				for(i = 0; i < TkTnumopts; i++) {					if(opts[i] == TkTunset && tags->opts[i] != TkTunset)						opts[i] = tags->opts[i];				}			} 			te = tags->env;			for(i = 0; i < TkNcolor; i++)				if(!(colset & (1<<i)) && te->set & (1<<i)) {					e->colors[i] = te->colors[i];					colset |= 1<<i;				} 			if(e->font == nil && te->font != nil)				e->font = te->font; 			if (tb != nil && tags->tabs != nil)				*tb = tags->tabs;		}		tags = tags->next;	}	e->set |= colset;	if(dflt) {		if(opts != nil) {			for(i = 0; i < TkTnumopts; i++)				if(opts[i] == TkTunset)					opts[i] = tkt->opts[i];		}		te = tk->env;		for(i = 0; i < TkNcolor; i++)			if(!(e->set & (1<<i))) {				e->colors[i] = te->colors[i];				e->set |= 1<<i;			}		if(e->font == nil)			e->font = te->font;	}} char*tkttagparse(Tk *tk, char **parg, TkTtaginfo **ret){	char *e, *buf;	TkText *tkt = TKobj(TkText, tk); 	buf = mallocz(Tkmaxitem, 0);	if(buf == nil)		return TkNomem;	*parg = tkword(tk->env->top, *parg, buf, buf+Tkmaxitem, nil);	if(*buf == '\0') {		free(buf);		return TkOparg;	}	if(buf[0] >= '0' && buf[0] <= '9'){		free(buf);		return TkBadtg;	} 	*ret = tktfindtag(tkt->tags, buf);	if(*ret == nil) {		e = tktaddtaginfo(tk, buf, ret);		if(e != nil) {			free(buf);			return e;		}	}	free(buf); 	return nil;} inttkttagnrange(TkText *tkt, int tid, TkTindex *i1, TkTindex *i2,			TkTindex *istart, TkTindex *iend){	int found; 	found = 0;	while(i1->line != &tkt->end) {		if(i1->item == i2->item && i2->pos == 0)			break;		if(tkttagset(i1->item, tid)) {			if(!found) {				found = 1;				*istart = *i1;			}			if(i1->item == i2->item) {				/* i2->pos > 0 */				*iend = *i2;				return 1;			}		}		else		if(i1->item == i2->item || (found && i1->item->kind != TkTmark && i1->item->kind != TkTcontline))			break;		tktadjustind(tkt, TkTbyitem, i1);	}	if(found)		*iend = *i1; 	return found;} static inttkttagprange(TkText *tkt, int tid, TkTindex *i1, TkTindex *i2,			TkTindex *istart, TkTindex *iend){	int found; 	found = 0;	while(i1->line != &tkt->start && i1->item != i2->item) {		tktadjustind(tkt, TkTbyitemback, i1);		if(tkttagset(i1->item, tid)) {			if(!found) {				found = 1;				*iend = *i1;			}		}		else		if(found && i1->item->kind != TkTmark && i1->item->kind != TkTcontline)			break;	}	if(found) {		tktadjustind(tkt, TkTbyitem, i1);		*istart = *i1;		if(i1->item == i2->item)			istart->pos = i2->pos;	} 	return found;} /* XXX - Tad: potential memory leak on memory allocation failure */char *tkttagchange(Tk *tk, int tid, TkTindex *i1, TkTindex *i2, int add){	char *e;	int samei, nextra, j, changed;	TkTline *lmin, *lmax;	TkTindex ixprev;	TkTitem *nit;	TkText *tkt = TKobj(TkText, tk); 	if(!tktindbefore(i1, i2))		return nil; 	nextra = tid/32;	lmin = nil;	lmax = nil;	tktadjustind(tkt, TkTbycharstart, i1);	tktadjustind(tkt, TkTbycharstart, i2);	samei = (i1->item == i2->item);	if(i2->pos != 0) {		e = tktsplititem(i2);		if(e != nil)			return e;		if(samei) {			/* split means i1 should now point to previous item */			ixprev = *i2;

Lines 1–500 of 1029.