137da2899SCharles.Forsyth #include "lib9.h"
237da2899SCharles.Forsyth #include "draw.h"
337da2899SCharles.Forsyth #include "tk.h"
437da2899SCharles.Forsyth #include "textw.h"
537da2899SCharles.Forsyth
637da2899SCharles.Forsyth #define istring u.string
737da2899SCharles.Forsyth #define iwin u.win
837da2899SCharles.Forsyth #define imark u.mark
937da2899SCharles.Forsyth #define iline u.line
1037da2899SCharles.Forsyth
1137da2899SCharles.Forsyth /* debugging */
1237da2899SCharles.Forsyth extern int tktdbg;
1337da2899SCharles.Forsyth extern void tktprinttext(TkText*);
1437da2899SCharles.Forsyth extern void tktprintindex(TkTindex*);
1537da2899SCharles.Forsyth extern void tktprintitem(TkTitem*);
1637da2899SCharles.Forsyth extern void tktprintline(TkTline*);
1737da2899SCharles.Forsyth
1837da2899SCharles.Forsyth char*
tktindparse(Tk * tk,char ** pspec,TkTindex * ans)1937da2899SCharles.Forsyth tktindparse(Tk *tk, char **pspec, TkTindex *ans)
2037da2899SCharles.Forsyth {
2137da2899SCharles.Forsyth int m, n, done, neg, modstart;
2237da2899SCharles.Forsyth char *s, *mod;
2337da2899SCharles.Forsyth TkTline *lend;
2437da2899SCharles.Forsyth TkText *tkt;
2537da2899SCharles.Forsyth char *buf;
2637da2899SCharles.Forsyth
2737da2899SCharles.Forsyth buf = mallocz(Tkmaxitem, 0);
2837da2899SCharles.Forsyth if(buf == nil)
2937da2899SCharles.Forsyth return TkNomem;
3037da2899SCharles.Forsyth
3137da2899SCharles.Forsyth tkt = TKobj(TkText, tk);
3237da2899SCharles.Forsyth lend = &tkt->end;
3337da2899SCharles.Forsyth
3437da2899SCharles.Forsyth *pspec = tkword(tk->env->top, *pspec, buf, buf+Tkmaxitem, nil);
3537da2899SCharles.Forsyth modstart = 0;
3637da2899SCharles.Forsyth for(mod = buf; *mod != '\0'; mod++)
3737da2899SCharles.Forsyth if(*mod == ' ' || *mod == '-' || *mod == '+') {
3837da2899SCharles.Forsyth modstart = *mod;
3937da2899SCharles.Forsyth *mod = '\0';
4037da2899SCharles.Forsyth break;
4137da2899SCharles.Forsyth }
4237da2899SCharles.Forsyth
4337da2899SCharles.Forsyth /*
4437da2899SCharles.Forsyth * XXX there's a problem here - if either coordinate is negative
4537da2899SCharles.Forsyth * which shouldn't be precluded, then the above scanning code
4637da2899SCharles.Forsyth * will break up the coordinate pair, so @-23,45 for example
4737da2899SCharles.Forsyth * yields a bad index, when it should probably return the index
4837da2899SCharles.Forsyth * of the character at the start of the line containing y=45.
4937da2899SCharles.Forsyth * i've seen this cause wm/sh to crash.
5037da2899SCharles.Forsyth */
5137da2899SCharles.Forsyth if(strcmp(buf, "end") == 0)
5237da2899SCharles.Forsyth tktendind(tkt, ans);
5337da2899SCharles.Forsyth else
5437da2899SCharles.Forsyth if(*buf == '@') {
5537da2899SCharles.Forsyth /* by coordinates */
5637da2899SCharles.Forsyth
5737da2899SCharles.Forsyth s = strchr(buf, ',');
5837da2899SCharles.Forsyth if(s == nil) {
5937da2899SCharles.Forsyth free(buf);
6037da2899SCharles.Forsyth return TkBadix;
6137da2899SCharles.Forsyth }
6237da2899SCharles.Forsyth *s = '\0';
6337da2899SCharles.Forsyth m = atoi(buf+1);
6437da2899SCharles.Forsyth n = atoi(s+1);
6537da2899SCharles.Forsyth tktxyind(tk, m, n, ans);
6637da2899SCharles.Forsyth }
6737da2899SCharles.Forsyth else
6837da2899SCharles.Forsyth if(*buf >= '0' && *buf <= '9') {
6937da2899SCharles.Forsyth /* line.char */
7037da2899SCharles.Forsyth
7137da2899SCharles.Forsyth s = strchr(buf, '.');
7237da2899SCharles.Forsyth if(s == nil) {
7337da2899SCharles.Forsyth free(buf);
7437da2899SCharles.Forsyth return TkBadix;
7537da2899SCharles.Forsyth }
7637da2899SCharles.Forsyth *s = '\0';
7737da2899SCharles.Forsyth m = atoi(buf);
7837da2899SCharles.Forsyth n = atoi(s+1);
7937da2899SCharles.Forsyth
8037da2899SCharles.Forsyth if(m < 1)
8137da2899SCharles.Forsyth m = 1;
8237da2899SCharles.Forsyth
8337da2899SCharles.Forsyth tktstartind(tkt, ans);
8437da2899SCharles.Forsyth
8537da2899SCharles.Forsyth while(--m > 0 && ans->line->next != lend)
8637da2899SCharles.Forsyth tktadjustind(tkt, TkTbyline, ans);
8737da2899SCharles.Forsyth
8837da2899SCharles.Forsyth while(n-- > 0 && ans->item->kind != TkTnewline)
8937da2899SCharles.Forsyth tktadjustind(tkt, TkTbychar, ans);
9037da2899SCharles.Forsyth }
9137da2899SCharles.Forsyth else
9237da2899SCharles.Forsyth if(*buf == '.') {
9337da2899SCharles.Forsyth /* window */
9437da2899SCharles.Forsyth
9537da2899SCharles.Forsyth tktstartind(tkt, ans);
9637da2899SCharles.Forsyth
9737da2899SCharles.Forsyth while(ans->line != lend) {
9837da2899SCharles.Forsyth if(ans->item->kind == TkTwin &&
9937da2899SCharles.Forsyth ans->item->iwin->sub != nil &&
10037da2899SCharles.Forsyth ans->item->iwin->sub->name != nil &&
10137da2899SCharles.Forsyth strcmp(ans->item->iwin->sub->name->name, buf) == 0)
10237da2899SCharles.Forsyth break;
10337da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbyitem, ans))
10437da2899SCharles.Forsyth ans->line = lend;
10537da2899SCharles.Forsyth }
10637da2899SCharles.Forsyth if(ans->line == lend) {
10737da2899SCharles.Forsyth free(buf);
10837da2899SCharles.Forsyth return TkBadix;
10937da2899SCharles.Forsyth }
11037da2899SCharles.Forsyth }
11137da2899SCharles.Forsyth else {
11237da2899SCharles.Forsyth s = strchr(buf, '.');
11337da2899SCharles.Forsyth if(s == nil) {
11437da2899SCharles.Forsyth if(tktmarkind(tk, buf, ans) == 0) {
11537da2899SCharles.Forsyth free(buf);
11637da2899SCharles.Forsyth return TkBadix;
11737da2899SCharles.Forsyth }
11837da2899SCharles.Forsyth }
11937da2899SCharles.Forsyth else {
12037da2899SCharles.Forsyth /* tag.first or tag.last */
12137da2899SCharles.Forsyth
12237da2899SCharles.Forsyth *s = '\0';
12337da2899SCharles.Forsyth if(strcmp(s+1, "first") == 0) {
12437da2899SCharles.Forsyth if(tkttagind(tk, buf, 1, ans) == 0) {
12537da2899SCharles.Forsyth free(buf);
12637da2899SCharles.Forsyth return TkBadix;
12737da2899SCharles.Forsyth }
12837da2899SCharles.Forsyth }
12937da2899SCharles.Forsyth else
13037da2899SCharles.Forsyth if(strcmp(s+1, "last") == 0) {
13137da2899SCharles.Forsyth if(tkttagind(tk, buf, 0, ans) == 0) {
13237da2899SCharles.Forsyth free(buf);
13337da2899SCharles.Forsyth return TkBadix;
13437da2899SCharles.Forsyth }
13537da2899SCharles.Forsyth }
13637da2899SCharles.Forsyth else {
13737da2899SCharles.Forsyth free(buf);
13837da2899SCharles.Forsyth return TkBadix;
13937da2899SCharles.Forsyth }
14037da2899SCharles.Forsyth }
14137da2899SCharles.Forsyth }
14237da2899SCharles.Forsyth
14337da2899SCharles.Forsyth if(modstart == 0) {
14437da2899SCharles.Forsyth free(buf);
14537da2899SCharles.Forsyth return nil;
14637da2899SCharles.Forsyth }
14737da2899SCharles.Forsyth
14837da2899SCharles.Forsyth *mod = modstart;
14937da2899SCharles.Forsyth while(*mod == ' ')
15037da2899SCharles.Forsyth mod++;
15137da2899SCharles.Forsyth
15237da2899SCharles.Forsyth while(*mod != '\0') {
15337da2899SCharles.Forsyth done = 0;
15437da2899SCharles.Forsyth switch(*mod) {
15537da2899SCharles.Forsyth case '+':
15637da2899SCharles.Forsyth case '-':
15737da2899SCharles.Forsyth neg = (*mod == '-');
15837da2899SCharles.Forsyth mod++;
15937da2899SCharles.Forsyth while(*mod == ' ')
16037da2899SCharles.Forsyth mod++;
16137da2899SCharles.Forsyth n = strtol(mod, &mod, 10);
16237da2899SCharles.Forsyth while(*mod == ' ')
16337da2899SCharles.Forsyth mod++;
16437da2899SCharles.Forsyth while(n-- > 0) {
16537da2899SCharles.Forsyth if(*mod == 'c')
16637da2899SCharles.Forsyth tktadjustind(tkt, neg? TkTbycharback : TkTbychar, ans);
16737da2899SCharles.Forsyth else
16837da2899SCharles.Forsyth if(*mod == 'l')
16937da2899SCharles.Forsyth tktadjustind(tkt, neg? TkTbylineback : TkTbyline, ans);
17037da2899SCharles.Forsyth else
17137da2899SCharles.Forsyth done = 1;
17237da2899SCharles.Forsyth }
17337da2899SCharles.Forsyth break;
17437da2899SCharles.Forsyth case 'l':
17537da2899SCharles.Forsyth if(strncmp(mod, "lines", 5) == 0)
17637da2899SCharles.Forsyth tktadjustind(tkt, TkTbylinestart, ans);
17737da2899SCharles.Forsyth else
17837da2899SCharles.Forsyth if(strncmp(mod, "linee", 5) == 0)
17937da2899SCharles.Forsyth tktadjustind(tkt, TkTbylineend, ans);
18037da2899SCharles.Forsyth else
18137da2899SCharles.Forsyth done = 1;
18237da2899SCharles.Forsyth break;
18337da2899SCharles.Forsyth case 'w':
18437da2899SCharles.Forsyth if(strncmp(mod, "words", 5) == 0)
18537da2899SCharles.Forsyth tktadjustind(tkt, TkTbywordstart, ans);
18637da2899SCharles.Forsyth else
18737da2899SCharles.Forsyth if(strncmp(mod, "worde", 5) == 0)
18837da2899SCharles.Forsyth tktadjustind(tkt, TkTbywordend, ans);
18937da2899SCharles.Forsyth else
19037da2899SCharles.Forsyth done = 1;
19137da2899SCharles.Forsyth break;
19237da2899SCharles.Forsyth default:
19337da2899SCharles.Forsyth done = 1;
19437da2899SCharles.Forsyth }
19537da2899SCharles.Forsyth
19637da2899SCharles.Forsyth if(done)
19737da2899SCharles.Forsyth break;
19837da2899SCharles.Forsyth
19937da2899SCharles.Forsyth while(tkiswordchar(*mod))
20037da2899SCharles.Forsyth mod++;
20137da2899SCharles.Forsyth while(*mod == ' ')
20237da2899SCharles.Forsyth mod++;
20337da2899SCharles.Forsyth }
20437da2899SCharles.Forsyth
20537da2899SCharles.Forsyth free(buf);
20637da2899SCharles.Forsyth return nil;
20737da2899SCharles.Forsyth }
20837da2899SCharles.Forsyth
20937da2899SCharles.Forsyth int
tktisbreak(int c)21037da2899SCharles.Forsyth tktisbreak(int c)
21137da2899SCharles.Forsyth {
21237da2899SCharles.Forsyth /* unicode rules suggest / as well but that would split dates, and URLs might as well char. wrap */
21337da2899SCharles.Forsyth return c == ' ' || c == '\t' || c == '\n' || c == '-' || c == ',';
21437da2899SCharles.Forsyth /* previously included . but would probably need more then to handle ." */
21537da2899SCharles.Forsyth }
21637da2899SCharles.Forsyth
21737da2899SCharles.Forsyth /*
21837da2899SCharles.Forsyth * Adjust the index p by units (one of TkTbyitem, etc.).
21937da2899SCharles.Forsyth * The TkTbychar units mean that the final point should rest on a
22037da2899SCharles.Forsyth * "character" (in text widget index space; i.e., a newline, a rune,
22137da2899SCharles.Forsyth * and an embedded window are each 1 character, but marks and contlines are not).
22237da2899SCharles.Forsyth *
22337da2899SCharles.Forsyth * Indexes may not point in the tkt->start or tkt->end lines (which have
22437da2899SCharles.Forsyth * no items); tktadjustind sticks at the beginning or end of the buffer.
22537da2899SCharles.Forsyth *
22637da2899SCharles.Forsyth * Return 1 if the index changes at all, 0 otherwise.
22737da2899SCharles.Forsyth */
22837da2899SCharles.Forsyth int
tktadjustind(TkText * tkt,int units,TkTindex * p)22937da2899SCharles.Forsyth tktadjustind(TkText *tkt, int units, TkTindex *p)
23037da2899SCharles.Forsyth {
23137da2899SCharles.Forsyth int n, opos, count, c;
23237da2899SCharles.Forsyth TkTitem *i, *it, *oit;
23337da2899SCharles.Forsyth TkTindex q;
23437da2899SCharles.Forsyth
23537da2899SCharles.Forsyth oit = p->item;
23637da2899SCharles.Forsyth opos = p->pos;
23737da2899SCharles.Forsyth count = 1;
23837da2899SCharles.Forsyth
23937da2899SCharles.Forsyth switch(units) {
24037da2899SCharles.Forsyth case TkTbyitemback:
24137da2899SCharles.Forsyth it = p->item;
24237da2899SCharles.Forsyth p->item = p->line->items;
24337da2899SCharles.Forsyth p->pos = 0;
24437da2899SCharles.Forsyth if(it == p->item) {
24537da2899SCharles.Forsyth if(p->line->prev != &tkt->start) {
24637da2899SCharles.Forsyth p->line = p->line->prev;
24737da2899SCharles.Forsyth p->item = tktlastitem(p->line->items);
24837da2899SCharles.Forsyth }
24937da2899SCharles.Forsyth }
25037da2899SCharles.Forsyth else {
25137da2899SCharles.Forsyth while(p->item->next != it) {
25237da2899SCharles.Forsyth p->item = p->item->next;
25337da2899SCharles.Forsyth if(tktdbg && p->item == nil) {
25437da2899SCharles.Forsyth print("tktadjustind: botch 1\n");
25537da2899SCharles.Forsyth break;
25637da2899SCharles.Forsyth }
25737da2899SCharles.Forsyth }
25837da2899SCharles.Forsyth }
25937da2899SCharles.Forsyth break;
26037da2899SCharles.Forsyth
26137da2899SCharles.Forsyth case TkTbyitem:
26237da2899SCharles.Forsyth p->pos = 0;
26337da2899SCharles.Forsyth i = p->item->next;
26437da2899SCharles.Forsyth if(i == nil) {
26537da2899SCharles.Forsyth if(p->line->next != &tkt->end) {
26637da2899SCharles.Forsyth p->line = p->line->next;
26737da2899SCharles.Forsyth p->item = p->line->items;
26837da2899SCharles.Forsyth }
26937da2899SCharles.Forsyth }
27037da2899SCharles.Forsyth else
27137da2899SCharles.Forsyth p->item = i;
27237da2899SCharles.Forsyth break;
27337da2899SCharles.Forsyth
27437da2899SCharles.Forsyth case TkTbytlineback:
27537da2899SCharles.Forsyth if(p->line->prev != &tkt->start)
27637da2899SCharles.Forsyth p->line = p->line->prev;
27737da2899SCharles.Forsyth p->item = p->line->items;
27837da2899SCharles.Forsyth p->pos = 0;
27937da2899SCharles.Forsyth break;
28037da2899SCharles.Forsyth
28137da2899SCharles.Forsyth case TkTbytline:
28237da2899SCharles.Forsyth if(p->line->next != &tkt->end)
28337da2899SCharles.Forsyth p->line = p->line->next;
28437da2899SCharles.Forsyth p->item = p->line->items;
28537da2899SCharles.Forsyth p->pos = 0;
28637da2899SCharles.Forsyth break;
28737da2899SCharles.Forsyth
28837da2899SCharles.Forsyth case TkTbycharstart:
28937da2899SCharles.Forsyth count = 0;
29037da2899SCharles.Forsyth case TkTbychar:
29137da2899SCharles.Forsyth while(count > 0) {
29237da2899SCharles.Forsyth i = p->item;
29337da2899SCharles.Forsyth n = tktposcount(i) - p->pos;
29437da2899SCharles.Forsyth if(count >= n) {
29537da2899SCharles.Forsyth if(tktadjustind(tkt, TkTbyitem, p))
29637da2899SCharles.Forsyth count -= n;
29737da2899SCharles.Forsyth else
29837da2899SCharles.Forsyth break;
29937da2899SCharles.Forsyth }
30037da2899SCharles.Forsyth else {
30137da2899SCharles.Forsyth p->pos += count;
30237da2899SCharles.Forsyth break;
30337da2899SCharles.Forsyth }
30437da2899SCharles.Forsyth }
30537da2899SCharles.Forsyth while(p->item->kind == TkTmark || p->item->kind == TkTcontline)
30637da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbyitem, p))
30737da2899SCharles.Forsyth break;
30837da2899SCharles.Forsyth break;
30937da2899SCharles.Forsyth case TkTbycharback:
31037da2899SCharles.Forsyth count = -1;
31137da2899SCharles.Forsyth while(count < 0) {
31237da2899SCharles.Forsyth if(p->pos + count >= 0) {
31337da2899SCharles.Forsyth p->pos += count;
31437da2899SCharles.Forsyth count = 0;
31537da2899SCharles.Forsyth }
31637da2899SCharles.Forsyth else {
31737da2899SCharles.Forsyth count += p->pos;
31837da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbyitemback, p))
31937da2899SCharles.Forsyth break;
32037da2899SCharles.Forsyth n = tktposcount(p->item);
32137da2899SCharles.Forsyth p->pos = n;
32237da2899SCharles.Forsyth }
32337da2899SCharles.Forsyth }
32437da2899SCharles.Forsyth break;
32537da2899SCharles.Forsyth
32637da2899SCharles.Forsyth case TkTbylineback:
32737da2899SCharles.Forsyth count = -1;
32837da2899SCharles.Forsyth /* fall through */
32937da2899SCharles.Forsyth case TkTbyline:
33037da2899SCharles.Forsyth n = tktlinepos(tkt, p);
33137da2899SCharles.Forsyth while(count > 0) {
33237da2899SCharles.Forsyth if(p->line->next == &tkt->end) {
33337da2899SCharles.Forsyth count = 0;
33437da2899SCharles.Forsyth break;
33537da2899SCharles.Forsyth }
33637da2899SCharles.Forsyth if(p->line->flags&TkTlast)
33737da2899SCharles.Forsyth count--;
33837da2899SCharles.Forsyth p->line = p->line->next;
33937da2899SCharles.Forsyth }
34037da2899SCharles.Forsyth while(count < 0 && p->line->prev != &tkt->start) {
34137da2899SCharles.Forsyth if(p->line->flags&TkTfirst)
34237da2899SCharles.Forsyth count++;
34337da2899SCharles.Forsyth p->line = p->line->prev;
34437da2899SCharles.Forsyth }
34537da2899SCharles.Forsyth tktadjustind(tkt, TkTbylinestart, p);
34637da2899SCharles.Forsyth while(n > 0) {
34737da2899SCharles.Forsyth if(p->item->kind == TkTnewline)
34837da2899SCharles.Forsyth break;
34937da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbychar, p))
35037da2899SCharles.Forsyth break;
35137da2899SCharles.Forsyth n--;
35237da2899SCharles.Forsyth }
35337da2899SCharles.Forsyth break;
35437da2899SCharles.Forsyth
35537da2899SCharles.Forsyth case TkTbylinestart:
35637da2899SCharles.Forsyth /* note: can call this with only p->line set correctly in *p */
35737da2899SCharles.Forsyth
35837da2899SCharles.Forsyth while(!(p->line->flags&TkTfirst))
35937da2899SCharles.Forsyth p->line = p->line->prev;
36037da2899SCharles.Forsyth p->item = p->line->items;
36137da2899SCharles.Forsyth p->pos = 0;
36237da2899SCharles.Forsyth break;
36337da2899SCharles.Forsyth
36437da2899SCharles.Forsyth case TkTbylineend:
36537da2899SCharles.Forsyth while(p->item->kind != TkTnewline)
36637da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbychar, p))
36737da2899SCharles.Forsyth break;
36837da2899SCharles.Forsyth break;
36937da2899SCharles.Forsyth
37037da2899SCharles.Forsyth case TkTbywordstart:
37137da2899SCharles.Forsyth tktadjustind(tkt, TkTbycharstart, p);
37237da2899SCharles.Forsyth q = *p;
37337da2899SCharles.Forsyth c = tktindrune(p);
37437da2899SCharles.Forsyth while(tkiswordchar(c)) {
37537da2899SCharles.Forsyth q = *p;
37637da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbycharback, p))
37737da2899SCharles.Forsyth break;
37837da2899SCharles.Forsyth c = tktindrune(p);
37937da2899SCharles.Forsyth }
38037da2899SCharles.Forsyth *p = q;
38137da2899SCharles.Forsyth break;
38237da2899SCharles.Forsyth
38337da2899SCharles.Forsyth case TkTbywordend:
38437da2899SCharles.Forsyth tktadjustind(tkt, TkTbycharstart, p);
38537da2899SCharles.Forsyth if(p->item->kind == TkTascii || p->item->kind == TkTrune) {
38637da2899SCharles.Forsyth c = tktindrune(p);
38737da2899SCharles.Forsyth if(tkiswordchar(c)) {
38837da2899SCharles.Forsyth do {
38937da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbychar, p))
39037da2899SCharles.Forsyth break;
39137da2899SCharles.Forsyth c = tktindrune(p);
39237da2899SCharles.Forsyth } while(tkiswordchar(c));
39337da2899SCharles.Forsyth }
39437da2899SCharles.Forsyth else
39537da2899SCharles.Forsyth tktadjustind(tkt, TkTbychar, p);
39637da2899SCharles.Forsyth }
39737da2899SCharles.Forsyth else if(!(p->item->kind == TkTnewline && p->line->next == &tkt->end))
39837da2899SCharles.Forsyth tktadjustind(tkt, TkTbychar, p);
39937da2899SCharles.Forsyth
40037da2899SCharles.Forsyth break;
40137da2899SCharles.Forsyth
40237da2899SCharles.Forsyth case TkTbywrapstart:
40337da2899SCharles.Forsyth tktadjustind(tkt, TkTbycharstart, p);
40437da2899SCharles.Forsyth q = *p;
40537da2899SCharles.Forsyth c = tktindrune(p);
40637da2899SCharles.Forsyth while(!tktisbreak(c)) {
40737da2899SCharles.Forsyth q = *p;
40837da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbycharback, p))
40937da2899SCharles.Forsyth break;
41037da2899SCharles.Forsyth c = tktindrune(p);
41137da2899SCharles.Forsyth }
41237da2899SCharles.Forsyth *p = q;
41337da2899SCharles.Forsyth break;
41437da2899SCharles.Forsyth
41537da2899SCharles.Forsyth case TkTbywrapend:
41637da2899SCharles.Forsyth tktadjustind(tkt, TkTbycharstart, p);
41737da2899SCharles.Forsyth if(p->item->kind == TkTascii || p->item->kind == TkTrune) {
41837da2899SCharles.Forsyth c = tktindrune(p);
41937da2899SCharles.Forsyth if(!tktisbreak(c)) {
42037da2899SCharles.Forsyth do {
42137da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbychar, p))
42237da2899SCharles.Forsyth break;
42337da2899SCharles.Forsyth c = tktindrune(p);
42437da2899SCharles.Forsyth } while(!tktisbreak(c) && (p->item->kind == TkTascii || p->item->kind == TkTrune));
42537da2899SCharles.Forsyth while(tktisbreak(c) && tktadjustind(tkt, TkTbychar, p))
42637da2899SCharles.Forsyth c = tktindrune(p); /* could limit it */
42737da2899SCharles.Forsyth }
42837da2899SCharles.Forsyth else
42937da2899SCharles.Forsyth tktadjustind(tkt, TkTbychar, p);
43037da2899SCharles.Forsyth }
43137da2899SCharles.Forsyth else if(!(p->item->kind == TkTnewline && p->line->next == &tkt->end))
43237da2899SCharles.Forsyth tktadjustind(tkt, TkTbychar, p);
43337da2899SCharles.Forsyth
43437da2899SCharles.Forsyth break;
43537da2899SCharles.Forsyth }
43637da2899SCharles.Forsyth return (p->item != oit || p->pos != opos);
43737da2899SCharles.Forsyth }
43837da2899SCharles.Forsyth
43937da2899SCharles.Forsyth /* return 1 if advancing i1 by item eventually hits i2 */
44037da2899SCharles.Forsyth int
tktindbefore(TkTindex * i1,TkTindex * i2)44137da2899SCharles.Forsyth tktindbefore(TkTindex *i1, TkTindex *i2)
44237da2899SCharles.Forsyth {
44337da2899SCharles.Forsyth int ans;
44437da2899SCharles.Forsyth TkTitem *i;
44537da2899SCharles.Forsyth TkTline *l1, *l2;
44637da2899SCharles.Forsyth
44737da2899SCharles.Forsyth ans = 0;
44837da2899SCharles.Forsyth l1 = i1->line;
44937da2899SCharles.Forsyth l2 = i2->line;
45037da2899SCharles.Forsyth
45137da2899SCharles.Forsyth if(l1 == l2) {
45237da2899SCharles.Forsyth if(i1->item == i2->item)
45337da2899SCharles.Forsyth ans = (i1->pos < i2->pos);
45437da2899SCharles.Forsyth else {
45537da2899SCharles.Forsyth for(i = i1->item; i != nil; i = i->next)
45637da2899SCharles.Forsyth if(i->next == i2->item) {
45737da2899SCharles.Forsyth ans = 1;
45837da2899SCharles.Forsyth break;
45937da2899SCharles.Forsyth }
46037da2899SCharles.Forsyth }
46137da2899SCharles.Forsyth }
46237da2899SCharles.Forsyth else {
46337da2899SCharles.Forsyth if(l1->orig.y < l2->orig.y)
46437da2899SCharles.Forsyth ans = 1;
46537da2899SCharles.Forsyth else
46637da2899SCharles.Forsyth if(l1->orig.y == l2->orig.y) {
46737da2899SCharles.Forsyth for(; l1 != nil; l1 = l1->next) {
46837da2899SCharles.Forsyth if(l1->next == l2) {
46937da2899SCharles.Forsyth ans = 1;
47037da2899SCharles.Forsyth break;
47137da2899SCharles.Forsyth }
47237da2899SCharles.Forsyth if(l1->orig.y > l2->orig.y)
47337da2899SCharles.Forsyth break;
47437da2899SCharles.Forsyth }
47537da2899SCharles.Forsyth }
47637da2899SCharles.Forsyth }
47737da2899SCharles.Forsyth
47837da2899SCharles.Forsyth return ans;
47937da2899SCharles.Forsyth }
48037da2899SCharles.Forsyth
48137da2899SCharles.Forsyth /*
48237da2899SCharles.Forsyth * This comparison only cares which characters the indices are before.
48337da2899SCharles.Forsyth * So two marks should be called "equal" (and not "less" or "greater")
48437da2899SCharles.Forsyth * if they are adjacent.
48537da2899SCharles.Forsyth */
48637da2899SCharles.Forsyth int
tktindcompare(TkText * tkt,TkTindex * i1,int op,TkTindex * i2)48737da2899SCharles.Forsyth tktindcompare(TkText *tkt, TkTindex *i1, int op, TkTindex *i2)
48837da2899SCharles.Forsyth {
48937da2899SCharles.Forsyth int eq, ans;
49037da2899SCharles.Forsyth TkTindex x1, x2;
49137da2899SCharles.Forsyth
49237da2899SCharles.Forsyth x1 = *i1;
49337da2899SCharles.Forsyth x2 = *i2;
49437da2899SCharles.Forsyth
49537da2899SCharles.Forsyth /* skip over any marks, contlines, to see if on same character */
49637da2899SCharles.Forsyth tktadjustind(tkt, TkTbycharstart, &x1);
49737da2899SCharles.Forsyth tktadjustind(tkt, TkTbycharstart, &x2);
49837da2899SCharles.Forsyth eq = (x1.item == x2.item && x1.pos == x2.pos);
49937da2899SCharles.Forsyth
50037da2899SCharles.Forsyth switch(op) {
50137da2899SCharles.Forsyth case TkEq:
50237da2899SCharles.Forsyth ans = eq;
50337da2899SCharles.Forsyth break;
50437da2899SCharles.Forsyth case TkNeq:
50537da2899SCharles.Forsyth ans = !eq;
50637da2899SCharles.Forsyth break;
50737da2899SCharles.Forsyth case TkLte:
50837da2899SCharles.Forsyth ans = eq || tktindbefore(i1, i2);
50937da2899SCharles.Forsyth break;
51037da2899SCharles.Forsyth case TkLt:
51137da2899SCharles.Forsyth ans = !eq && tktindbefore(i1, i2);
51237da2899SCharles.Forsyth break;
51337da2899SCharles.Forsyth case TkGte:
51437da2899SCharles.Forsyth ans = eq || tktindbefore(i2, i1);
51537da2899SCharles.Forsyth break;
51637da2899SCharles.Forsyth case TkGt:
51737da2899SCharles.Forsyth ans = !eq && tktindbefore(i2, i1);
51837da2899SCharles.Forsyth break;
51937da2899SCharles.Forsyth default:
520*6e425a9dSCharles.Forsyth ans = 0; /* not reached */
521*6e425a9dSCharles.Forsyth break;
52237da2899SCharles.Forsyth };
52337da2899SCharles.Forsyth
52437da2899SCharles.Forsyth return ans;
52537da2899SCharles.Forsyth }
52637da2899SCharles.Forsyth
52737da2899SCharles.Forsyth void
tktstartind(TkText * tkt,TkTindex * ans)52837da2899SCharles.Forsyth tktstartind(TkText *tkt, TkTindex *ans)
52937da2899SCharles.Forsyth {
53037da2899SCharles.Forsyth ans->line = tkt->start.next;
53137da2899SCharles.Forsyth ans->item = ans->line->items;
53237da2899SCharles.Forsyth ans->pos = 0;
53337da2899SCharles.Forsyth }
53437da2899SCharles.Forsyth
53537da2899SCharles.Forsyth void
tktendind(TkText * tkt,TkTindex * ans)53637da2899SCharles.Forsyth tktendind(TkText *tkt, TkTindex *ans)
53737da2899SCharles.Forsyth {
53837da2899SCharles.Forsyth ans->line = tkt->end.prev;
53937da2899SCharles.Forsyth ans->item = tktlastitem(ans->line->items);
54037da2899SCharles.Forsyth ans->pos = 0;
54137da2899SCharles.Forsyth }
54237da2899SCharles.Forsyth
54337da2899SCharles.Forsyth void
tktitemind(TkTitem * it,TkTindex * ans)54437da2899SCharles.Forsyth tktitemind(TkTitem *it, TkTindex *ans)
54537da2899SCharles.Forsyth {
54637da2899SCharles.Forsyth ans->item = it;
54737da2899SCharles.Forsyth ans->line = tktitemline(it);
54837da2899SCharles.Forsyth ans->pos = 0;
54937da2899SCharles.Forsyth }
55037da2899SCharles.Forsyth
55137da2899SCharles.Forsyth /*
55237da2899SCharles.Forsyth * Fill ans with the item that (x,y) (in V space) is over.
55337da2899SCharles.Forsyth * Return 0 if it is over the first half of the width,
55437da2899SCharles.Forsyth * and 1 if it is over the second half.
55537da2899SCharles.Forsyth */
55637da2899SCharles.Forsyth int
tktxyind(Tk * tk,int x,int y,TkTindex * ans)55737da2899SCharles.Forsyth tktxyind(Tk *tk, int x, int y, TkTindex *ans)
55837da2899SCharles.Forsyth {
55937da2899SCharles.Forsyth int n, w, secondhalf, k;
56037da2899SCharles.Forsyth Point p, q;
56137da2899SCharles.Forsyth TkTitem *i;
56237da2899SCharles.Forsyth TkText *tkt;
56337da2899SCharles.Forsyth
56437da2899SCharles.Forsyth tkt = TKobj(TkText, tk);
56537da2899SCharles.Forsyth tktstartind(tkt, ans);
56637da2899SCharles.Forsyth secondhalf = 0;
56737da2899SCharles.Forsyth
56837da2899SCharles.Forsyth /* (x,y), p, q in V space */
56937da2899SCharles.Forsyth p = subpt(ans->line->orig, tkt->deltatv);
57037da2899SCharles.Forsyth q = subpt(ans->line->next->orig, tkt->deltatv);
57137da2899SCharles.Forsyth while(ans->line->next != &tkt->end) {
57237da2899SCharles.Forsyth if(q.y > y)
57337da2899SCharles.Forsyth break;
57437da2899SCharles.Forsyth tktadjustind(tkt, TkTbytline, ans);
57537da2899SCharles.Forsyth p = q;
57637da2899SCharles.Forsyth q = subpt(ans->line->next->orig, tkt->deltatv);
57737da2899SCharles.Forsyth }
57837da2899SCharles.Forsyth if (ans->line->next == &tkt->end) {
57937da2899SCharles.Forsyth Point ep = subpt(tkt->end.orig, tkt->deltatv);
58037da2899SCharles.Forsyth if (ep.y < y)
58137da2899SCharles.Forsyth x = 1000000;
58237da2899SCharles.Forsyth }
58337da2899SCharles.Forsyth
58437da2899SCharles.Forsyth while(ans->item->next != nil) {
58537da2899SCharles.Forsyth i = ans->item;
58637da2899SCharles.Forsyth w = i->width;
58737da2899SCharles.Forsyth if(p.x+w > x) {
58837da2899SCharles.Forsyth n = tktposcount(i);
58937da2899SCharles.Forsyth if(n > 1) {
59037da2899SCharles.Forsyth for(k = 0; k < n; k++) {
59137da2899SCharles.Forsyth /* probably wrong w.r.t tag tabs */
59237da2899SCharles.Forsyth w = tktdispwidth(tk, nil, i, nil, p.x, k, 1);
59337da2899SCharles.Forsyth if(p.x+w > x) {
59437da2899SCharles.Forsyth ans->pos = k;
59537da2899SCharles.Forsyth break;
59637da2899SCharles.Forsyth }
59737da2899SCharles.Forsyth p.x += w;
59837da2899SCharles.Forsyth }
59937da2899SCharles.Forsyth }
60037da2899SCharles.Forsyth secondhalf = (p.x + w/2 <= x);
60137da2899SCharles.Forsyth break;
60237da2899SCharles.Forsyth }
60337da2899SCharles.Forsyth p.x += w;
60437da2899SCharles.Forsyth if(!tktadjustind(tkt, TkTbyitem, ans))
60537da2899SCharles.Forsyth break;
60637da2899SCharles.Forsyth }
60737da2899SCharles.Forsyth tktadjustind(tkt, TkTbycharstart, ans);
60837da2899SCharles.Forsyth return secondhalf;
60937da2899SCharles.Forsyth }
61037da2899SCharles.Forsyth
611