|
|
1.1 ! root 1: /* Cursor motion subroutines for GNU Emacs. ! 2: Copyright (C) 1985 Richard M. Stallman. ! 3: based primarily on public domain code written by Chris Torek ! 4: ! 5: This file is part of GNU Emacs. ! 6: ! 7: GNU Emacs is distributed in the hope that it will be useful, ! 8: but WITHOUT ANY WARRANTY. No author or distributor ! 9: accepts responsibility to anyone for the consequences of using it ! 10: or for whether it serves any particular purpose or works at all, ! 11: unless he says so in writing. Refer to the GNU Emacs General Public ! 12: License for full details. ! 13: ! 14: Everyone is granted permission to copy, modify and redistribute ! 15: GNU Emacs, but only under the conditions described in the ! 16: GNU Emacs General Public License. A copy of this license is ! 17: supposed to have been given to you along with GNU Emacs so you ! 18: can know your rights and responsibilities. It should be in a ! 19: file named COPYING. Among other things, the copyright notice ! 20: and this notice must be preserved on all copies. */ ! 21: ! 22: ! 23: #include "config.h" ! 24: #include <stdio.h> ! 25: #include "cm.h" ! 26: #include "termhooks.h" ! 27: ! 28: #define BIG 9999 /* 9999 good on VAXen. For 16 bit machines ! 29: use about 2000.... */ ! 30: ! 31: char *malloc (), *tgoto (), *getenv (); ! 32: ! 33: extern char *BC, *UP; ! 34: ! 35: int cost; /* sums up costs */ ! 36: ! 37: /* ARGSUSED */ ! 38: evalcost (c) ! 39: char c; ! 40: { ! 41: cost++; ! 42: } ! 43: ! 44: void ! 45: cmputc (c) ! 46: char c; ! 47: { ! 48: if (termscript) ! 49: fputc (c & 0177, termscript); ! 50: putchar (c & 0177); ! 51: } ! 52: ! 53: /* NEXT TWO ARE DONE WITH MACROS */ ! 54: #if 0 ! 55: /* ! 56: * Assume the cursor is at row row, column col. Normally used only after ! 57: * clearing the screen, when the cursor is at (0, 0), but what the heck, ! 58: * let's let the guy put it anywhere. ! 59: */ ! 60: ! 61: static ! 62: at (row, col) { ! 63: curY = row; ! 64: curX = col; ! 65: } ! 66: ! 67: /* ! 68: * Add n columns to the current cursor position. ! 69: */ ! 70: ! 71: static ! 72: addcol (n) { ! 73: curX += n; ! 74: ! 75: /* ! 76: * If cursor hit edge of screen, what happened? ! 77: * N.B.: DO NOT!! write past edge of screen. If you do, you ! 78: * deserve what you get. Furthermore, on terminals with ! 79: * autowrap (but not magicwrap), don't write in the last column ! 80: * of the last line. ! 81: */ ! 82: ! 83: if (curX == Wcm.cm_cols) { ! 84: /* ! 85: * Well, if magicwrap, still there, past the edge of the ! 86: * screen (!). If autowrap, on the col 0 of the next line. ! 87: * Otherwise on last column. ! 88: */ ! 89: ! 90: if (Wcm.cm_magicwrap) ! 91: ; /* "limbo" */ ! 92: else if (Wcm.cm_autowrap) { ! 93: curX = 0; ! 94: curY++; /* Beware end of screen! */ ! 95: } ! 96: else ! 97: curX--; ! 98: } ! 99: } ! 100: #endif ! 101: ! 102: /* ! 103: * (Re)Initialize the cost factors, given the output speed of the terminal ! 104: * in the variable ospeed. (Note: this holds B300, B9600, etc -- ie stuff ! 105: * out of <sgtty.h>.) ! 106: */ ! 107: ! 108: cmcostinit () ! 109: { ! 110: char *p; ! 111: ! 112: #define COST(x,e) (x ? (cost = 0, tputs (x, 1, e), cost) : BIG) ! 113: #define CMCOST(x,e) ((x == 0) ? BIG : (p = tgoto(x, 0, 0), COST(p ,e))) ! 114: ! 115: Wcm.cc_up = COST (Wcm.cm_up, evalcost); ! 116: Wcm.cc_down = COST (Wcm.cm_down, evalcost); ! 117: Wcm.cc_left = COST (Wcm.cm_left, evalcost); ! 118: Wcm.cc_right = COST (Wcm.cm_right, evalcost); ! 119: Wcm.cc_home = COST (Wcm.cm_home, evalcost); ! 120: Wcm.cc_cr = COST (Wcm.cm_cr, evalcost); ! 121: Wcm.cc_ll = COST (Wcm.cm_ll, evalcost); ! 122: Wcm.cc_tab = Wcm.cm_tabwidth ? COST (Wcm.cm_tab, evalcost) : BIG; ! 123: ! 124: /* ! 125: * These last three are actually minimum costs. When (if) they are ! 126: * candidates for the least-cost motion, the real cost is computed. ! 127: * (Note that "0" is the assumed to generate the minimum cost. ! 128: * While this is not necessarily true, I have yet to see a terminal ! 129: * for which is not; all the terminals that have variable-cost ! 130: * cursor motion seem to take straight numeric values. --ACT) ! 131: */ ! 132: ! 133: Wcm.cc_abs = CMCOST (Wcm.cm_abs, evalcost); ! 134: Wcm.cc_habs = CMCOST (Wcm.cm_habs, evalcost); ! 135: Wcm.cc_vabs = CMCOST (Wcm.cm_vabs, evalcost); ! 136: ! 137: #undef CMCOST ! 138: #undef COST ! 139: } ! 140: ! 141: /* ! 142: * Calculate the cost to move from (srcy, srcx) to (dsty, dstx) using ! 143: * up and down, and left and right, motions, and tabs. If doit is set ! 144: * actually perform the motion. ! 145: */ ! 146: ! 147: static ! 148: calccost (srcy, srcx, dsty, dstx, doit) ! 149: { ! 150: register int deltay, ! 151: deltax, ! 152: c, ! 153: totalcost; ! 154: int ntabs, ! 155: n2tabs, ! 156: tabx, ! 157: tab2x, ! 158: tabcost; ! 159: register char *p; ! 160: ! 161: /* If have just wrapped on a terminal with xn, ! 162: don't believe the cursor position: give up here ! 163: and force use of absolute positioning. */ ! 164: ! 165: if (curX == Wcm.cm_cols) ! 166: goto fail; ! 167: ! 168: totalcost = 0; ! 169: if ((deltay = dsty - srcy) == 0) ! 170: goto x; ! 171: if (deltay < 0) ! 172: p = Wcm.cm_up, c = Wcm.cc_up, deltay = -deltay; ! 173: else ! 174: p = Wcm.cm_down, c = Wcm.cc_down; ! 175: if (c == BIG) { /* caint get thar from here */ ! 176: if (doit) ! 177: printf ("OOPS"); ! 178: return c; ! 179: } ! 180: totalcost = c * deltay; ! 181: if (doit) ! 182: while (--deltay >= 0) ! 183: tputs (p, 1, cmputc); ! 184: x: ! 185: if ((deltax = dstx - srcx) == 0) ! 186: goto done; ! 187: if (deltax < 0) { ! 188: p = Wcm.cm_left, c = Wcm.cc_left, deltax = -deltax; ! 189: goto dodelta; /* skip all the tab junk */ ! 190: } ! 191: /* Tabs (the toughie) */ ! 192: if (Wcm.cc_tab >= BIG || !Wcm.cm_usetabs) ! 193: goto olddelta; /* forget it! */ ! 194: ! 195: /* ! 196: * ntabs is # tabs towards but not past dstx; n2tabs is one more ! 197: * (ie past dstx), but this is only valid if that is not past the ! 198: * right edge of the screen. We can check that at the same time ! 199: * as we figure out where we would be if we use the tabs (which ! 200: * we will put into tabx (for ntabs) and tab2x (for n2tabs)). ! 201: */ ! 202: ! 203: ntabs = deltax / Wcm.cm_tabwidth; ! 204: n2tabs = ntabs + 1; ! 205: tabx = (srcx / Wcm.cm_tabwidth + ntabs) * Wcm.cm_tabwidth; ! 206: tab2x = tabx + Wcm.cm_tabwidth; ! 207: ! 208: if (tab2x >= Wcm.cm_cols) /* too far (past edge) */ ! 209: n2tabs = 0; ! 210: ! 211: /* ! 212: * Now set tabcost to the cost for using ntabs, and c to the cost ! 213: * for using n2tabs, then pick the minimum. ! 214: */ ! 215: ! 216: /* cost for ntabs + cost for right motion */ ! 217: tabcost = ntabs ? ntabs * Wcm.cc_tab + (dstx - tabx) * Wcm.cc_right ! 218: : BIG; ! 219: ! 220: /* cost for n2tabs + cost for left motion */ ! 221: c = n2tabs ? n2tabs * Wcm.cc_tab + (tab2x - dstx) * Wcm.cc_left ! 222: : BIG; ! 223: ! 224: if (c < tabcost) /* then cheaper to overshoot & back up */ ! 225: ntabs = n2tabs, tabcost = c, tabx = tab2x; ! 226: ! 227: if (tabcost >= BIG) /* caint use tabs */ ! 228: goto newdelta; ! 229: ! 230: /* ! 231: * See if tabcost is less than just moving right ! 232: */ ! 233: ! 234: if (tabcost < (deltax * Wcm.cc_right)) { ! 235: totalcost += tabcost; /* use the tabs */ ! 236: if (doit) ! 237: while (--ntabs >= 0) ! 238: tputs (Wcm.cm_tab, 1, cmputc); ! 239: srcx = tabx; ! 240: } ! 241: ! 242: /* ! 243: * Now might as well just recompute the delta. ! 244: */ ! 245: ! 246: newdelta: ! 247: if ((deltax = dstx - srcx) == 0) ! 248: goto done; ! 249: olddelta: ! 250: if (deltax > 0) ! 251: p = Wcm.cm_right, c = Wcm.cc_right; ! 252: else ! 253: p = Wcm.cm_left, c = Wcm.cc_left, deltax = -deltax; ! 254: ! 255: dodelta: ! 256: if (c == BIG) { /* caint get thar from here */ ! 257: fail: ! 258: if (doit) ! 259: printf ("OOPS"); ! 260: return BIG; ! 261: } ! 262: totalcost += c * deltax; ! 263: if (doit) ! 264: while (--deltax >= 0) ! 265: tputs (p, 1, cmputc); ! 266: done: ! 267: return totalcost; ! 268: } ! 269: ! 270: losecursor () ! 271: { ! 272: curY = -1; ! 273: } ! 274: ! 275: #define USEREL 0 ! 276: #define USEHOME 1 ! 277: #define USELL 2 ! 278: #define USECR 3 ! 279: ! 280: cmgoto (row, col) ! 281: { ! 282: int homecost, ! 283: crcost, ! 284: llcost, ! 285: relcost, ! 286: directcost; ! 287: int use; ! 288: char *p, ! 289: *dcm; ! 290: ! 291: /* First the degenerate case */ ! 292: if (row == curY && col == curX) /* already there */ ! 293: return; ! 294: ! 295: if (curY >= 0 && curX >= 0) ! 296: { ! 297: /* ! 298: * Pick least-cost motions ! 299: */ ! 300: ! 301: relcost = calccost (curY, curX, row, col, 0); ! 302: use = USEREL; ! 303: if ((homecost = Wcm.cc_home) < BIG) ! 304: homecost += calccost (0, 0, row, col, 0); ! 305: if (homecost < relcost) ! 306: relcost = homecost, use = USEHOME; ! 307: if ((llcost = Wcm.cc_ll) < BIG) ! 308: llcost += calccost (Wcm.cm_rows - 1, 0, row, col, 0); ! 309: if (llcost < relcost) ! 310: relcost = llcost, use = USELL; ! 311: if ((crcost = Wcm.cc_cr) < BIG) { ! 312: if (Wcm.cm_autolf) ! 313: if (curY + 1 >= Wcm.cm_rows) ! 314: crcost = BIG; ! 315: else ! 316: crcost += calccost (curY + 1, 0, row, col, 0); ! 317: else ! 318: crcost += calccost (curY, 0, row, col, 0); ! 319: } ! 320: if (crcost < relcost) ! 321: relcost = crcost, use = USECR; ! 322: directcost = Wcm.cc_abs, dcm = Wcm.cm_abs; ! 323: if (row == curY && Wcm.cc_habs < BIG) ! 324: directcost = Wcm.cc_habs, dcm = Wcm.cm_habs; ! 325: else if (col == curX && Wcm.cc_vabs < BIG) ! 326: directcost = Wcm.cc_vabs, dcm = Wcm.cm_vabs; ! 327: } ! 328: else ! 329: { ! 330: directcost = 0, relcost = 100000; ! 331: dcm = Wcm.cm_abs; ! 332: } ! 333: ! 334: /* ! 335: * In the following comparison, the = in <= is because when the costs ! 336: * are the same, it looks nicer (I think) to move directly there. ! 337: */ ! 338: if (directcost <= relcost) ! 339: { ! 340: /* compute REAL direct cost */ ! 341: cost = 0; ! 342: p = dcm == Wcm.cm_habs ? tgoto (dcm, row, col) : ! 343: tgoto (dcm, col, row); ! 344: tputs (p, 1, evalcost); ! 345: if (cost <= relcost) ! 346: { /* really is cheaper */ ! 347: tputs (p, 1, cmputc); ! 348: curY = row, curX = col; ! 349: return; ! 350: } ! 351: } ! 352: ! 353: switch (use) ! 354: { ! 355: case USEHOME: ! 356: tputs (Wcm.cm_home, 1, cmputc); ! 357: curY = 0, curX = 0; ! 358: break; ! 359: ! 360: case USELL: ! 361: tputs (Wcm.cm_ll, 1, cmputc); ! 362: curY = Wcm.cm_rows - 1, curX = 0; ! 363: break; ! 364: ! 365: case USECR: ! 366: tputs (Wcm.cm_cr, 1, cmputc); ! 367: if (Wcm.cm_autolf) ! 368: curY++; ! 369: curX = 0; ! 370: break; ! 371: } ! 372: ! 373: (void) calccost (curY, curX, row, col, 1); ! 374: curY = row, curX = col; ! 375: } ! 376: ! 377: /* Clear out all terminal info. ! 378: Used before copying into it the info on the actual terminal. ! 379: */ ! 380: ! 381: Wcm_clear () ! 382: { ! 383: bzero (&Wcm, sizeof Wcm); ! 384: UP = 0; ! 385: BC = 0; ! 386: } ! 387: ! 388: /* ! 389: * Initialized stuff ! 390: * Return 0 if can do CM. ! 391: */ ! 392: ! 393: Wcm_init () ! 394: { ! 395: /* Check that we know the size of the screen.... */ ! 396: if (Wcm.cm_rows <= 0 || Wcm.cm_cols <= 0) ! 397: return - 1; ! 398: if (Wcm.cm_abs && !Wcm.cm_ds) ! 399: return 0; ! 400: /* Require up and left, and, if no absolute, down and right */ ! 401: if (!Wcm.cm_up || !Wcm.cm_left) ! 402: return - 1; ! 403: if (!Wcm.cm_abs && (!Wcm.cm_down || !Wcm.cm_right)) ! 404: return - 1; ! 405: return 0; ! 406: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.