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