#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. Load more
#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 }; TkCmdtab tkttagcmd[] = { "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 }; int tktanytags(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; } int tktsametags(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; } int tkttagset(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 */ int tkttagbit(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; } void tkttagcomb(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; } void tktfreetags(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; } } int tkttagind(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. */ void tkttagopts(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; } int tkttagnrange(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 int tkttagprange(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;