|
|
1.1 root 1: #include "curses.ext"
2: /* @(#) mvcur.c: 1.1 10/15/83 (1.14 3/16/83) */
3:
4:
5: /*
6: * Cursor motion optimization routine. This routine takes as parameters
7: * the screen positions that the cursor is currently at, and the position
8: * you want it to be at, and it will move the cursor there very
9: * efficiently. It isn't really optimal, since several approximations
10: * are taken in the interests of efficiency and simplicity. The code
11: * here considers directly addressing the cursor, and also considers
12: * local motions using left, right, up, down, tabs, backtabs, vertical
13: * and horizontal addressing, and parameterized motions. It does not
14: * consider using home down, or taking advantage of automatic margins on
15: * any of the four directions. (Two of these directions, left and right,
16: * are well defined by the am and bw capabilities, but up and down are
17: * not defined, nor are tab or backtab off the ends.)
18: *
19: * General strategies considered:
20: * CA Direct Cursor Addressing
21: * LM Local Motions from the old position
22: * HDR Home + Local Motions from upper left corner
23: * CR CR + Local Motions from left margin
24: *
25: * Local Motions can include
26: * Up cuu, cuu1, vpa
27: * Down cud, cud1, vpa
28: * Left cul, cul1, hpa, bs, cbt
29: * Right cuf, cuf1, hpa, tab, char moved over
30: */
31:
32: #ifdef DEBUG
33: /* We don't want this debugging output now. */
34: # undef DEBUG
35: #endif
36:
37: /* #define mvcurdebug */
38:
39: #ifdef mvcurdebug
40: # define DEBUG
41: # define _outch oc
42: FILE *outf;
43: main()
44: {
45: int oldrow, oldcol, newrow, newcol, n;
46:
47: newterm(getenv("TERM"), stdout, stdin);
48: echo();
49: nocrmode();
50: nl();
51: outf = stdout;
52: setbuf(stdout, NULL);
53: for (;;) {
54: printf("oldrow, oldcol, newrow, newcol: ");
55: n = scanf("%d %d %d %d", &oldrow, &oldcol, &newrow, &newcol);
56: if (n < 0) {
57: endwin();
58: exit(1);
59: }
60: mvcur(oldrow, oldcol, newrow, newcol);
61: }
62: }
63:
64: _outch(ch)
65: {
66: printf("_outch '%s'\n", unctrl(ch));
67: }
68: #else
69: int _outch();
70: #endif
71:
72: static int bare_lf_ok; /* bare_lf_ok is true if linefeed will work right */
73: char *tparm();
74:
75: mvcur(oldrow, oldcol, newrow, newcol)
76: int oldrow, oldcol, newrow, newcol;
77: {
78: /* temporary costs of various submotions */
79: int home_right; /* cost to move from col 0 right to newcol */
80: int cur_right; /* motion from current postition to right */
81: int cur_left; /* motion from current postition to left */
82: int home_down; /* motion from line 0 downward */
83: int cur_down; /* motion from current position downward */
84: int cur_up; /* motion from current position upward */
85: /* costs of various full motions we consider */
86: int cost_ca; /* cost of directly addressing the cursor */
87: int cost_hdr; /* going home, local motions down & right */
88: int cost_cr; /* return, local motions up/down & right */
89: int cost_lm; /* local motions up/down & left/right */
90: int sgf;
91:
92: #ifdef DEBUG
93: if(outf) fprintf(outf, "mvcur(oldrow=%d, oldcol=%d, newrow=%d, newcol=%d)\n",
94: oldrow, oldcol, newrow, newcol);
95: #endif
96: /* Quick check for nothing to do - very common case. */
97: if (oldrow == newrow && oldcol == newcol)
98: return;
99: #ifndef NONSTANDARD
100: # ifdef USG
101: bare_lf_ok = ((cur_term->Nttyb.c_oflag&ONLCR)==0);
102: # else
103: sgf = cur_term->Nttyb.sg_flags;
104: bare_lf_ok = (sgf&RAW) ? 1 : (sgf&CRMOD)==0;
105: # endif
106: #else NONSTANDARD
107: bare_lf_ok = 1;
108: #endif NONSTANDARD
109: /* Another common case: crlf */
110: if (newcol==0 && newrow==oldrow+1 && carriage_return && cursor_down) {
111: /*
112: * Just because bare_lf_ok is on doesn't mean cursor_down is
113: * crlf. E.g. in the tty 40/2 it's escape B. The test below
114: * will be wrong on a newline style terminal (!bare_lf_ok)
115: * with no carriage_return where cursor_down is not crlf.
116: * I have never seen such a terminal.
117: */
118: if (oldcol > 0 && carriage_return)
119: tputs(carriage_return, 1, _outch);
120: tputs(cursor_down, 1, _outch);
121: return;
122: }
123:
124: /* Figure out costs of various component motions */
125: home_right = _loc_right(0 , newcol, 0, newcol);
126: cur_right = _loc_right(oldcol, newcol, 0, newcol);
127: cur_left = _loc_left (oldcol, newcol, 0);
128: home_down = _loc_down (0 , newrow, 0, newcol);
129: cur_down = _loc_down (oldrow, newrow, 0, newcol);
130: cur_up = _loc_up (oldrow, newrow, 0);
131: #ifdef DEBUG
132: if(outf) fprintf(outf, "home_right %d, cur_right %d, cur_left %d, home_down %d, cur_down %d, cur_up %d\n",
133: home_right, cur_right, cur_left, home_down, cur_down, cur_up);
134: #endif
135:
136: /* 4 possible strategies: get costs for each */
137: cost_ca = _cost(Cursor_address);
138: cost_hdr = _cost(Cursor_home) + home_down + home_right;
139: /* 3rd and 4th strategies: local motions and with carriage return. */
140: if (newrow < oldrow) {
141: if (newcol < oldcol)
142: cost_lm = cur_left + cur_up;
143: else
144: cost_lm = cur_right + cur_up;
145: cost_cr = _cost(Carriage_return) + cur_up + home_right;
146: } else {
147: if (newcol < oldcol)
148: cost_lm = cur_left + cur_down;
149: else
150: cost_lm = cur_right + cur_down;
151: if (cur_down >= INFINITY)
152: cur_down = _loc_down(oldrow, newrow, 0, 0);
153: cost_cr = _cost(Carriage_return) + cur_down + home_right;
154: }
155:
156: #ifdef DEBUG
157: if(outf) fprintf(outf, "cost_ca %d, cost_hdr %d, cost_cr %d, cost_lm %d\n",
158: cost_ca, cost_hdr, cost_cr, cost_lm);
159: #endif
160: /*
161: * Now we pick which one is cheapest and actually do it.
162: * Note the ordering if they come out equal - this was
163: * conciously chosen based on how visually distracting
164: * it is to see the cursor bounce all over the screen,
165: * I did not take into account approximation errors.
166: */
167: if (cost_ca <= cost_hdr && cost_ca <= cost_cr && cost_ca <= cost_lm) {
168: /* direct cursor addressing is cheapest */
169: #ifdef DEBUG
170: if(outf) fprintf(outf, "chose absolute cursor addressing\n");
171: #endif
172: tputs(tparm(cursor_address, newrow, newcol), 1, _outch);
173: } else if (cost_lm <= cost_cr && cost_lm <= cost_hdr) {
174: /* local motions are cheapest */
175: #ifdef DEBUG
176: if(outf) fprintf(outf, "chose local motions\n");
177: #endif
178: if (newcol > oldcol) {
179: if (newrow > oldrow)
180: (void) _loc_down(oldrow, newrow, 1, newcol);
181: else
182: (void) _loc_up(oldrow, newrow, 1);
183: (void) _loc_right(oldcol, newcol, 1, newrow);
184: } else {
185: if (newrow > oldrow)
186: (void) _loc_down(oldrow, newrow, 1, newcol);
187: else
188: (void) _loc_up(oldrow, newrow, 1);
189: (void) _loc_left(oldcol, newcol, 1);
190: }
191: } else if (cost_cr <= cost_hdr) {
192: /* carriage return + local motions are cheapest */
193: #ifdef DEBUG
194: if(outf) fprintf(outf, "chose carriage return + local motions\n");
195: #endif
196: tputs(carriage_return, 1, _outch);
197: if (newrow > oldrow)
198: (void) _loc_down(oldrow, newrow, 1, 0);
199: else
200: (void) _loc_up(oldrow, newrow, 1);
201: (void) _loc_right(0, newcol, 1, newrow);
202: } else {
203: /* home + local motions are cheapest */
204: #ifdef DEBUG
205: if(outf) fprintf(outf, "chose home + local motions\n");
206: #endif
207: tputs(cursor_home, 1, _outch);
208: (void) _loc_down(0, newrow, 1, newcol);
209: (void) _loc_right(0, newcol, 1, newrow);
210: }
211: #ifdef DEBUG
212: if(outf) fprintf(outf, "end of mvcur\n");
213: #endif
214: }
215:
216: /*
217: * These four routines figure out what the cost of the most efficient
218: * kind of local motion from the given row or column to the other given
219: * row or column is. They return the cost, in characters. If the third
220: * argument is 1, they actually do the motion. The row number is useful
221: * if we're going to actually do the motion - that way we can look in
222: * the screen image (if we have it) and just output the characters that
223: * are already on the screen - this usually saves 50% over cursor_right.
224: */
225: static
226: _loc_right(oldcol, newcol, domotion, row)
227: {
228: int c0, c1, c2, c3;
229: int i, tabcol, ntabs, nright, nleft;
230: /* notinsmode: we know for sure we aren't in insert char mode */
231: int notinsmode = SP && SP->phys_irm!=1;
232: register struct line *rp;
233:
234: if (newcol < oldcol) /* can't go left with right motions */
235: return INFINITY;
236: if (newcol == oldcol)
237: return 0; /* already there - nothing to do */
238: #ifdef DEBUG
239: fprintf(outf, "SP %x, phys_irm %d, notinsmode %d\n",
240: SP, SP->phys_irm, notinsmode);
241: #endif
242:
243: /*
244: * Code here and further down attempts to output the character that
245: * is already on the screen to move right.
246: */
247: if (notinsmode)
248: _cost(Cursor_right) = 1;
249: else
250: _cost(Cursor_right) = _cost(Right_base);
251: /* figure out various costs */
252:
253: tabcol = (newcol+4)/8 * 8; /* round to nearest 8 */
254: /* tab past right margin is undefined */
255: if (tabcol >= columns)
256: tabcol = (columns-1)/8 * 8;
257: ntabs = (tabcol-oldcol+7)/8;
258: if (ntabs <= 0)
259: tabcol = oldcol;
260: if (tabcol < newcol) {
261: /* some tabs plus some rights */
262: nright = newcol - tabcol;
263: c1 = ntabs*_cost(Tab) + nright*_cost(Cursor_right);
264: } else {
265: /* some tabs plus some lefts */
266: nleft = tabcol - newcol;
267: c1 = ntabs*_cost(Tab) + nleft*_cost(Cursor_left);
268: }
269:
270: c0 = (newcol - oldcol) * _cost(Cursor_right);
271:
272: if (parm_right_cursor)
273: c2 = _cost(Parm_right_cursor);
274: else
275: c2 = INFINITY;
276:
277: if (column_address)
278: c3 = _cost(Column_address);
279: else
280: c3 = INFINITY;
281:
282: #ifdef DEBUG
283: if(outf) fprintf(outf, "_loc_right(%d, %d, %d), chars %d, ri %d, RI %d, ch %d\n",
284: oldcol, newcol, domotion, c0, c1, c2, c3);
285: #endif
286:
287: /* Decide and maybe do them */
288: if (c3 <= c1 && c3 <= c2 && c3 <= c0) {
289: /* cheapest to use column absolute cursor addressing */
290: #ifdef DEBUG
291: if(outf) fprintf(outf, "chose column absolute cursor addressing\n");
292: #endif
293: if (domotion)
294: tputs(tparm(column_address, newcol), 1, _outch);
295: return c3;
296: } else if (c2 <= c1 && c2 <= c0) {
297: /* cheapest to use column relative motion */
298: #ifdef DEBUG
299: if(outf) fprintf(outf, "chose column relative motion\n");
300: #endif
301: if (domotion)
302: tputs(tparm(parm_right_cursor, newcol-oldcol), 1, _outch);
303: return c2;
304: } else {
305: /* cheapest to use several right commands */
306: #ifdef DEBUG
307: if(outf) fprintf(outf, "chose rights: ntabs %d, tabcol %d, nleft %d, nright %d\n", ntabs, tabcol, nleft, nright);
308: #endif
309: if (domotion)
310: if (c1 < c0) {
311: for (i=0; i<ntabs; i++)
312: tputs(tab, 1, _outch);
313: if (tabcol < newcol) {
314: /* some tabs plus some rights */
315: for (i=0; i<nright; i++) {
316: #ifdef DEBUG
317: if (outf && SP->cur_body[row+1]) fprintf(outf, "nd1, row %d col %d+%d=%d, char '%c'\n",
318: row, tabcol, i, tabcol+i, SP->cur_body[row+1]->body[tabcol+i]);
319: #endif
320: rp = SP->cur_body[row+1];
321: if (cursor_right && (!notinsmode || rp && SP->phys_gr != (rp->body[tabcol+i] & A_ATTRIBUTES))) /* dont know */
322: tputs(cursor_right,1,_outch);
323: else if (rp && rp->length > tabcol+i)
324: /* Note we assume dumb terminals without cursor_right don't have
325: * standout either, otherwise we should go into right standout
326: * mode here and in the essentially similar code below.
327: */
328: _outch(rp->body[tabcol+i]&A_CHARTEXT);
329: else /* off edge */
330: _outch(' ');
331: }
332: } else {
333: /* some tabs plus some lefts */
334: for (i=0; i<nleft; i++)
335: tputs(cursor_left,1,_outch);
336: }
337: } else {
338: for (i=oldcol; i<newcol; i++) {
339: #ifdef DEBUG
340: if (outf && SP->cur_body[row+1]) fprintf(outf, "nd2, row %d col %d, char '%c'\n",
341: row, i, SP->cur_body[row+1]->body[i]);
342: #endif
343: rp = SP->cur_body[row+1];
344: if (cursor_right && (!notinsmode || rp && SP->phys_gr != (rp->body[i] & A_ATTRIBUTES))) /* dont know */
345: tputs(cursor_right,1,_outch);
346: else if (rp && rp->length > i)
347: _outch(rp->body[i]&A_CHARTEXT);
348: else /* off edge */
349: _outch(' ');
350: }
351: }
352: return (c1 < c0) ? c1 : c0;
353: }
354: }
355:
356: static
357: _loc_left(oldcol, newcol, domotion)
358: {
359: int c1, c2, c3;
360: int i, tabcol, ntabs, nright, nleft;
361:
362: if (newcol > oldcol) /* can't go right with left motions */
363: return INFINITY;
364: if (newcol == oldcol)
365: return 0; /* already there - nothing to do */
366:
367: /* figure out various costs */
368: if (cursor_left) {
369: if (back_tab) {
370: tabcol = (newcol+4)/8 * 8; /* round to nearest 8 */
371: /* tab past left margin is undefined */
372: if (tabcol < 8)
373: tabcol = 8;
374: ntabs = (oldcol-tabcol+7)/8;
375: if (ntabs <= 0)
376: tabcol = oldcol;
377: if (tabcol < newcol) {
378: /* some backtabs plus some rights */
379: nright = newcol - tabcol;
380: c1 = ntabs*_cost(Back_tab) + nright*_cost(Cursor_right);
381: } else {
382: /* some tabs plus some lefts */
383: nleft = tabcol - newcol;
384: c1 = ntabs*_cost(Back_tab) + nleft*_cost(Cursor_left);
385: }
386: } else {
387: c1 = (oldcol - newcol) * _cost(Cursor_left);
388: }
389: } else
390: c1 = INFINITY;
391: if (parm_left_cursor)
392: c2 = _cost(Parm_left_cursor);
393: else
394: c2 = INFINITY;
395: if (column_address)
396: c3 = _cost(Column_address);
397: else
398: c3 = INFINITY;
399:
400: #ifdef DEBUG
401: if(outf) fprintf(outf, "_loc_left(%d, %d, %d), le %d, LE %d, ch %d\n",
402: oldcol, newcol, domotion, c1, c2, c3);
403: #endif
404:
405: /* Decide and maybe do them */
406: if (c3 <= c1 && c3 <= c2) {
407: /* cheapest to use column absolute cursor addressing */
408: #ifdef DEBUG
409: if(outf) fprintf(outf, "chose column absolute cursor addressing\n");
410: #endif
411: if (domotion)
412: tputs(tparm(column_address, newcol), 1, _outch);
413: return c3;
414: } else if (c2 <= c1) {
415: /* cheapest to use column relative motion */
416: #ifdef DEBUG
417: if(outf) fprintf(outf, "chose column relative motion\n");
418: #endif
419: if (domotion)
420: tputs(tparm(parm_left_cursor, oldcol-newcol), 1, _outch);
421: return c2;
422: } else {
423: /* cheapest to use several left commands */
424: #ifdef DEBUG
425: if(outf) fprintf(outf, "chose several left commands\n");
426: #endif
427: if (domotion)
428: if (back_tab) {
429: for (i=0; i<ntabs; i++)
430: tputs(back_tab, 1, _outch);
431: if (tabcol < newcol) {
432: /* some tabs plus some rights */
433: for (i=0; i<nright; i++)
434: tputs(cursor_right,1, _outch);
435: } else {
436: /* some tabs plus some lefts */
437: for (i=0; i<nleft; i++)
438: tputs(cursor_left,1,_outch);
439: }
440: } else {
441: for (i=oldcol; i>newcol; i--)
442: tputs(cursor_left, 1, _outch);
443: }
444: return c1;
445: }
446: }
447:
448: static
449: _loc_up(oldrow, newrow, domotion)
450: {
451: int c1, c2, c3, i;
452:
453: if (newrow > oldrow) /* can't go down with up motions */
454: return INFINITY;
455: if (newrow == oldrow)
456: return 0; /* already there - nothing to do */
457:
458: /* figure out various costs */
459: if (cursor_up)
460: c1 = (oldrow - newrow) * _cost(Cursor_up);
461: else
462: c1 = INFINITY;
463: if (parm_up_cursor)
464: c2 = _cost(Parm_up_cursor);
465: else
466: c2 = INFINITY;
467: if (row_address)
468: c3 = _cost(Row_address);
469: else
470: c3 = INFINITY;
471:
472: #ifdef DEBUG
473: if(outf) fprintf(outf, "_loc_up(%d, %d, %d), up %d, UP %d, cv %d\n",
474: oldrow, newrow, domotion, c1, c2, c3);
475: #endif
476:
477: /* Decide and maybe do them */
478: if (c3 <= c1 && c3 <= c2) {
479: /* cheapest to use row absolute cursor addressing */
480: #ifdef DEBUG
481: if(outf) fprintf(outf, "chose row absolute cursor addressing\n");
482: #endif
483: if (domotion)
484: tputs(tparm(row_address, newrow), 1, _outch);
485: return c3;
486: } else if (c2 <= c1) {
487: /* cheapest to use row relative motion */
488: #ifdef DEBUG
489: if(outf) fprintf(outf, "chose row relative motion\n");
490: #endif
491: if (domotion)
492: tputs(tparm(parm_up_cursor, oldrow-newrow), 1, _outch);
493: return c2;
494: } else {
495: /* cheapest to use several up commands */
496: #ifdef DEBUG
497: if(outf) fprintf(outf, "chose several up commands\n");
498: #endif
499: if (domotion)
500: for (i=oldrow; i>newrow; i--)
501: tputs(cursor_up, 1, _outch);
502: return c1;
503: }
504: }
505:
506: static
507: _loc_down(oldrow, newrow, domotion, col)
508: {
509: int c1, c2, c3, i;
510:
511: if (newrow < oldrow) /* can't go up with down motions */
512: return INFINITY;
513: if (newrow == oldrow)
514: return 0; /* already there - nothing to do */
515:
516: /* figure out various costs */
517: if (cursor_down && (col==0 || bare_lf_ok || *cursor_down!='\n'))
518: c1 = (newrow - oldrow) * _cost(Cursor_down);
519: else
520: c1 = INFINITY;
521: if (parm_down_cursor)
522: c2 = _cost(Parm_down_cursor);
523: else
524: c2 = INFINITY;
525: if (row_address)
526: c3 = _cost(Row_address);
527: else
528: c3 = INFINITY;
529:
530: #ifdef DEBUG
531: if(outf) fprintf(outf, "_loc_down(%d, %d, %d, %d), do %d, DO %d, cv %d\n",
532: oldrow, newrow, domotion, col,c1, c2, c3);
533: #endif
534:
535: /* Decide and maybe do them */
536: if (c3 <= c1 && c3 <= c2) {
537: /* cheapest to use row absolute cursor addressing */
538: #ifdef DEBUG
539: if(outf) fprintf(outf, "chose row absolute cursor addressing\n");
540: #endif
541: if (domotion)
542: tputs(tparm(row_address, newrow), 1, _outch);
543: return c3;
544: } else if (c2 <= c1) {
545: /* cheapest to use row relative motion */
546: #ifdef DEBUG
547: if(outf) fprintf(outf, "chose row relative motion\n");
548: #endif
549: if (domotion)
550: tputs(tparm(parm_down_cursor, newrow-oldrow), 1, _outch);
551: return c2;
552: } else {
553: /* cheapest to use several down commands */
554: #ifdef DEBUG
555: if(outf) fprintf(outf, "chose several down commands\n");
556: #endif
557: if (domotion)
558: for (i=oldrow; i<newrow; i++)
559: tputs(cursor_down, 1, _outch);
560: return c1;
561: }
562: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.