home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / e20313sr.zip / emacs / 20.3.1 / src / cm.c < prev    next >
C/C++ Source or Header  |  1999-07-31  |  12KB  |  452 lines

  1. /* Cursor motion subroutines for GNU Emacs.
  2.    Copyright (C) 1985, 1995 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, Inc., 59 Temple Place - Suite 330,
  20. Boston, MA 02111-1307, USA.  */
  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 *tgoto ();
  32.  
  33. extern char *BC, *UP;
  34.  
  35. int cost;        /* sums up costs */
  36.  
  37. /* ARGSUSED */
  38. int
  39. evalcost (c)
  40.      char c;
  41. {
  42.   cost++;
  43.   return c;
  44. }
  45.  
  46. int
  47. cmputc (c)
  48.      char c;
  49. {
  50.   if (termscript)
  51.     fputc (c & 0177, termscript);
  52.   putchar (c & 0177);
  53.   return c;
  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.  * Terminals with magicwrap (xn) don't all behave identically.
  107.  * The VT100 leaves the cursor in the last column but will wrap before
  108.  * printing the next character.  I hear that the Concept terminal does
  109.  * the wrap immediately but ignores the next newline it sees.  And some
  110.  * terminals just have buggy firmware, and think that the cursor is still
  111.  * in limbo if we use direct cursor addressing from the phantom column.
  112.  * The only guaranteed safe thing to do is to emit a CRLF immediately
  113.  * after we reach the last column; this takes us to a known state.
  114.  */
  115. void
  116. cmcheckmagic ()
  117. {
  118.   if (curX == FrameCols)
  119.     {
  120.       if (!MagicWrap || curY >= FrameRows - 1)
  121.     abort ();
  122.       if (termscript)
  123.     putc ('\r', termscript);
  124.       putchar ('\r');
  125.       if (termscript)
  126.     putc ('\n', termscript);
  127.       putchar ('\n');
  128.       curX = 0;
  129.       curY++;
  130.     }
  131. }
  132.  
  133.  
  134. /*
  135.  * (Re)Initialize the cost factors, given the output speed of the terminal
  136.  * in the variable ospeed.  (Note: this holds B300, B9600, etc -- ie stuff
  137.  * out of <sgtty.h>.)
  138.  */
  139.  
  140. void
  141. cmcostinit ()
  142. {
  143.     char *p;
  144.  
  145. #define    COST(x,e)    (x ? (cost = 0, tputs (x, 1, e), cost) : BIG)
  146. #define CMCOST(x,e)    ((x == 0) ? BIG : (p = tgoto(x, 0, 0), COST(p ,e)))
  147.  
  148.     Wcm.cc_up =        COST (Wcm.cm_up, evalcost);
  149.     Wcm.cc_down =    COST (Wcm.cm_down, evalcost);
  150.     Wcm.cc_left =    COST (Wcm.cm_left, evalcost);
  151.     Wcm.cc_right =    COST (Wcm.cm_right, evalcost);
  152.     Wcm.cc_home =    COST (Wcm.cm_home, evalcost);
  153.     Wcm.cc_cr =        COST (Wcm.cm_cr, evalcost);
  154.     Wcm.cc_ll =        COST (Wcm.cm_ll, evalcost);
  155.     Wcm.cc_tab =    Wcm.cm_tabwidth ? COST (Wcm.cm_tab, evalcost) : BIG;
  156.  
  157.     /*
  158.      * These last three are actually minimum costs.  When (if) they are
  159.      * candidates for the least-cost motion, the real cost is computed.
  160.      * (Note that "0" is the assumed to generate the minimum cost.
  161.      * While this is not necessarily true, I have yet to see a terminal
  162.      * for which is not; all the terminals that have variable-cost
  163.      * cursor motion seem to take straight numeric values.  --ACT)
  164.      */
  165.  
  166.     Wcm.cc_abs =  CMCOST (Wcm.cm_abs, evalcost);
  167.     Wcm.cc_habs = CMCOST (Wcm.cm_habs, evalcost);
  168.     Wcm.cc_vabs = CMCOST (Wcm.cm_vabs, evalcost);
  169.  
  170. #undef CMCOST
  171. #undef COST
  172. }
  173.  
  174. /*
  175.  * Calculate the cost to move from (srcy, srcx) to (dsty, dstx) using
  176.  * up and down, and left and right, motions, and tabs.  If doit is set
  177.  * actually perform the motion.
  178.  */
  179.  
  180. static int
  181. calccost (srcy, srcx, dsty, dstx, doit)
  182. {
  183.     register int    deltay,
  184.                     deltax,
  185.                     c,
  186.                     totalcost;
  187.     int     ntabs,
  188.             n2tabs,
  189.             tabx,
  190.             tab2x,
  191.             tabcost;
  192.     register char  *p;
  193.  
  194.     /* If have just wrapped on a terminal with xn,
  195.        don't believe the cursor position: give up here
  196.        and force use of absolute positioning.  */
  197.  
  198.     if (curX == Wcm.cm_cols)
  199.       goto fail;
  200.  
  201.     totalcost = 0;
  202.     if ((deltay = dsty - srcy) == 0)
  203.     goto x;
  204.     if (deltay < 0)
  205.     p = Wcm.cm_up, c = Wcm.cc_up, deltay = -deltay;
  206.     else
  207.     p = Wcm.cm_down, c = Wcm.cc_down;
  208.     if (c == BIG) {        /* caint get thar from here */
  209.     if (doit)
  210.         printf ("OOPS");
  211.     return c;
  212.     }
  213.     totalcost = c * deltay;
  214.     if (doit)
  215.     while (--deltay >= 0)
  216.         tputs (p, 1, cmputc);
  217. x: 
  218.     if ((deltax = dstx - srcx) == 0)
  219.     goto done;
  220.     if (deltax < 0) {
  221.     p = Wcm.cm_left, c = Wcm.cc_left, deltax = -deltax;
  222.     goto dodelta;        /* skip all the tab junk */
  223.     }
  224.     /* Tabs (the toughie) */
  225.     if (Wcm.cc_tab >= BIG || !Wcm.cm_usetabs)
  226.     goto olddelta;        /* forget it! */
  227.  
  228.     /* 
  229.      * ntabs is # tabs towards but not past dstx; n2tabs is one more
  230.      * (ie past dstx), but this is only valid if that is not past the
  231.      * right edge of the screen.  We can check that at the same time
  232.      * as we figure out where we would be if we use the tabs (which
  233.      * we will put into tabx (for ntabs) and tab2x (for n2tabs)).
  234.      */
  235.  
  236.     ntabs = (deltax + srcx % Wcm.cm_tabwidth) / Wcm.cm_tabwidth;
  237.     n2tabs = ntabs + 1;
  238.     tabx = (srcx / Wcm.cm_tabwidth + ntabs) * Wcm.cm_tabwidth;
  239.     tab2x = tabx + Wcm.cm_tabwidth;
  240.  
  241.     if (tab2x >= Wcm.cm_cols)    /* too far (past edge) */
  242.     n2tabs = 0;
  243.  
  244.     /* 
  245.      * Now set tabcost to the cost for using ntabs, and c to the cost
  246.      * for using n2tabs, then pick the minimum.
  247.      */
  248.  
  249.            /* cost for ntabs     +    cost for right motion */
  250.     tabcost = ntabs ? ntabs * Wcm.cc_tab + (dstx - tabx) * Wcm.cc_right
  251.             : BIG;
  252.  
  253.            /* cost for n2tabs    +    cost for left motion */
  254.     c = n2tabs  ?    n2tabs * Wcm.cc_tab + (tab2x - dstx) * Wcm.cc_left
  255.         : BIG;
  256.  
  257.     if (c < tabcost)        /* then cheaper to overshoot & back up */
  258.     ntabs = n2tabs, tabcost = c, tabx = tab2x;
  259.  
  260.     if (tabcost >= BIG)        /* caint use tabs */
  261.     goto newdelta;
  262.  
  263.     /* 
  264.      * See if tabcost is less than just moving right
  265.      */
  266.  
  267.     if (tabcost < (deltax * Wcm.cc_right)) {
  268.     totalcost += tabcost;    /* use the tabs */
  269.     if (doit)
  270.         while (--ntabs >= 0)
  271.         tputs (Wcm.cm_tab, 1, cmputc);
  272.     srcx = tabx;
  273.     }
  274.  
  275.     /* 
  276.      * Now might as well just recompute the delta.
  277.      */
  278.  
  279. newdelta: 
  280.     if ((deltax = dstx - srcx) == 0)
  281.     goto done;
  282. olddelta: 
  283.     if (deltax > 0)
  284.     p = Wcm.cm_right, c = Wcm.cc_right;
  285.     else
  286.     p = Wcm.cm_left, c = Wcm.cc_left, deltax = -deltax;
  287.  
  288. dodelta: 
  289.     if (c == BIG) {        /* caint get thar from here */
  290. fail:
  291.     if (doit)
  292.         printf ("OOPS");
  293.     return BIG;
  294.     }
  295.     totalcost += c * deltax;
  296.     if (doit)
  297.     while (--deltax >= 0)
  298.         tputs (p, 1, cmputc);
  299. done: 
  300.     return totalcost;
  301. }
  302.  
  303. #if 0
  304. losecursor ()
  305. {
  306.   curY = -1;
  307. }
  308. #endif
  309.  
  310. #define    USEREL    0
  311. #define    USEHOME    1
  312. #define    USELL    2
  313. #define    USECR    3
  314.  
  315. void
  316. cmgoto (row, col)
  317. {
  318.     int     homecost,
  319.             crcost,
  320.             llcost,
  321.             relcost,
  322.             directcost;
  323.     int     use;
  324.     char   *p,
  325.            *dcm;
  326.  
  327.   /* First the degenerate case */
  328.   if (row == curY && col == curX) /* already there */
  329.     return;
  330.  
  331.   if (curY >= 0 && curX >= 0)
  332.     {
  333.       /* We may have quick ways to go to the upper-left, bottom-left,
  334.        * start-of-line, or start-of-next-line.  Or it might be best to
  335.        * start where we are.  Examine the options, and pick the cheapest.
  336.        */
  337.  
  338.       relcost = calccost (curY, curX, row, col, 0);
  339.       use = USEREL;
  340.       if ((homecost = Wcm.cc_home) < BIG)
  341.       homecost += calccost (0, 0, row, col, 0);
  342.       if (homecost < relcost)
  343.       relcost = homecost, use = USEHOME;
  344.       if ((llcost = Wcm.cc_ll) < BIG)
  345.       llcost += calccost (Wcm.cm_rows - 1, 0, row, col, 0);
  346.       if (llcost < relcost)
  347.       relcost = llcost, use = USELL;
  348.       if ((crcost = Wcm.cc_cr) < BIG) {
  349.       if (Wcm.cm_autolf)
  350.           if (curY + 1 >= Wcm.cm_rows)
  351.           crcost = BIG;
  352.           else
  353.           crcost += calccost (curY + 1, 0, row, col, 0);
  354.       else
  355.           crcost += calccost (curY, 0, row, col, 0);
  356.       }
  357.       if (crcost < relcost)
  358.       relcost = crcost, use = USECR;
  359.       directcost = Wcm.cc_abs, dcm = Wcm.cm_abs;
  360.       if (row == curY && Wcm.cc_habs < BIG)
  361.       directcost = Wcm.cc_habs, dcm = Wcm.cm_habs;
  362.       else if (col == curX && Wcm.cc_vabs < BIG)
  363.       directcost = Wcm.cc_vabs, dcm = Wcm.cm_vabs;
  364.     }
  365.   else
  366.     {
  367.       directcost = 0, relcost = 100000;
  368.       dcm = Wcm.cm_abs;
  369.     }
  370.  
  371.   /* 
  372.    * In the following comparison, the = in <= is because when the costs
  373.    * are the same, it looks nicer (I think) to move directly there.
  374.    */
  375.   if (directcost <= relcost)
  376.     {
  377.       /* compute REAL direct cost */
  378.       cost = 0;
  379.       p = dcm == Wcm.cm_habs ? tgoto (dcm, row, col) :
  380.                    tgoto (dcm, col, row);
  381.       tputs (p, 1, evalcost);
  382.       if (cost <= relcost)
  383.     {    /* really is cheaper */
  384.       tputs (p, 1, cmputc);
  385.       curY = row, curX = col;
  386.       return;
  387.     }
  388.     }
  389.  
  390.   switch (use)
  391.     {
  392.     case USEHOME: 
  393.       tputs (Wcm.cm_home, 1, cmputc);
  394.       curY = 0, curX = 0;
  395.       break;
  396.  
  397.     case USELL: 
  398.       tputs (Wcm.cm_ll, 1, cmputc);
  399.       curY = Wcm.cm_rows - 1, curX = 0;
  400.       break;
  401.  
  402.     case USECR: 
  403.       tputs (Wcm.cm_cr, 1, cmputc);
  404.       if (Wcm.cm_autolf)
  405.     curY++;
  406.       curX = 0;
  407.       break;
  408.     }
  409.  
  410.   (void) calccost (curY, curX, row, col, 1);
  411.   curY = row, curX = col;
  412. }
  413.  
  414. /* Clear out all terminal info.
  415.    Used before copying into it the info on the actual terminal.
  416.  */
  417.  
  418. void
  419. Wcm_clear ()
  420. {
  421.   bzero (&Wcm, sizeof Wcm);
  422.   UP = 0;
  423.   BC = 0;
  424. }
  425.  
  426. /*
  427.  * Initialized stuff
  428.  * Return 0 if can do CM.
  429.  * Return -1 if cannot.
  430.  * Return -2 if size not specified.
  431.  */
  432.  
  433. int
  434. Wcm_init ()
  435. {
  436. #if 0
  437.   if (Wcm.cm_abs && !Wcm.cm_ds)
  438.     return 0;
  439. #endif
  440.   if (Wcm.cm_abs)
  441.     return 0;
  442.   /* Require up and left, and, if no absolute, down and right */
  443.   if (!Wcm.cm_up || !Wcm.cm_left)
  444.     return - 1;
  445.   if (!Wcm.cm_abs && (!Wcm.cm_down || !Wcm.cm_right))
  446.     return - 1;
  447.   /* Check that we know the size of the screen.... */
  448.   if (Wcm.cm_rows <= 0 || Wcm.cm_cols <= 0)
  449.     return - 2;
  450.   return 0;
  451. }
  452.