Annotation of 43BSD/contrib/emacs/src/cm.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.