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: }

Defined functions

Wcm_clear defined in line 381; used 1 times
Wcm_init defined in line 393; used 1 times
addcol defined in line 71; never used
at defined in line 61; never used
calccost defined in line 147; used 6 times
cmcostinit defined in line 108; used 1 times
cmgoto defined in line 280; used 5 times
cmputc defined in line 44; used 8 times
evalcost defined in line 38; used 17 times
losecursor defined in line 270; used 2 times

Defined variables

cost defined in line 35; used 13 times

Defined macros

BIG defined in line 28; used 16 times
CMCOST defined in line 113; used 4 times
COST defined in line 112; used 10 times
USECR defined in line 278; used 1 times
USEHOME defined in line 276; used 1 times
USELL defined in line 277; used 1 times
USEREL defined in line 275; used 1 times
Last modified: 1986-04-08
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1322
Valid CSS Valid XHTML 1.0 Strict