home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / lucid / lemacs-19.6 / src / cm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-10  |  10.0 KB  |  426 lines

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