|
|
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.