home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / emacs-19.28-src.tgz / tar.out / fsf / emacs / src / cm.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  10KB  |  419 lines

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