home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / CMDS / memacs400_src.lzh / MEMACS400 / SRC / basic.c < prev    next >
Text File  |  1996-04-25  |  16KB  |  625 lines

  1. /*    basic.c:    Basic movement functions for
  2.  *            MicroEMACS
  3.  *            (C)Copyright 1995 by Daniel Lawrence
  4.  *
  5.  * The routines in this file move the cursor around on the screen. They
  6.  * compute a new value for the cursor, then adjust ".". The display code
  7.  * always updates the cursor location, so only moves between lines, or
  8.  * functions that adjust the top line in the window and invalidate the
  9.  * framing, are hard.
  10.  */
  11. #include    <stdio.h>
  12. #include    "estruct.h"
  13. #include    "eproto.h"
  14. #include    "edef.h"
  15. #include    "elang.h"
  16.  
  17. /*
  18.  * Move the cursor to the
  19.  * beginning of the current line.
  20.  * Trivial.
  21.  */
  22. PASCAL NEAR gotobol(f, n)
  23.  
  24. int f,n;    /* argument flag and num */
  25.  
  26. {
  27.         curwp->w_doto  = 0;
  28.         return(TRUE);
  29. }
  30.  
  31. /*
  32.  * Move the cursor backwards by "n" characters. If "n" is less than zero call
  33.  * "forwchar" to actually do the move. Otherwise compute the new cursor
  34.  * location. Error if you try and move out of the buffer. Set the flag if the
  35.  * line pointer for dot changes.
  36.  */
  37. PASCAL NEAR backchar(f, n)
  38.  
  39. int f,n;    /* prefix flag and argument */
  40.  
  41. {
  42.         register LINE   *lp;
  43.  
  44.         if (n < 0)
  45.                 return(forwchar(f, -n));
  46.         while (n--) {
  47.                 if (curwp->w_doto == 0) {
  48.                         if ((lp=lback(curwp->w_dotp)) == curbp->b_linep)
  49.                                 return(FALSE);
  50.                         curwp->w_dotp  = lp;
  51.                         curwp->w_doto  = lused(lp);
  52.                         curwp->w_flag |= WFMOVE;
  53.                 } else
  54.                         curwp->w_doto--;
  55.         }
  56. #if    DBCS
  57.     return(stopback());
  58. #else
  59.         return(TRUE);
  60. #endif
  61. }
  62.  
  63. /*
  64.  * Move the cursor to the end of the current line. Trivial. No errors.
  65.  */
  66. PASCAL NEAR gotoeol(f, n)
  67.  
  68. int f,n;    /* argument flag and num */
  69.  
  70. {
  71.         curwp->w_doto  = lused(curwp->w_dotp);
  72.         return(TRUE);
  73. }
  74.  
  75. /*
  76.  * Move the cursor forwards by "n" characters. If "n" is less than zero call
  77.  * "backchar" to actually do the move. Otherwise compute the new cursor
  78.  * location, and move ".". Error if you try and move off the end of the
  79.  * buffer. Set the flag if the line pointer for dot changes.
  80.  */
  81. PASCAL NEAR forwchar(f, n)
  82.  
  83. int f,n;    /* prefix flag and argument */
  84.  
  85. {
  86.         if (n < 0)
  87.                 return(backchar(f, -n));
  88.         while (n--) {
  89.                 if (curwp->w_doto == lused(curwp->w_dotp)) {
  90.                         if (curwp->w_dotp == curbp->b_linep)
  91.                                 return(FALSE);
  92.                         curwp->w_dotp  = lforw(curwp->w_dotp);
  93.                         curwp->w_doto  = 0;
  94.                         curwp->w_flag |= WFMOVE;
  95.                 } else
  96.                         curwp->w_doto++;
  97.         }
  98. #if    DBCS
  99.     return(stopforw());
  100. #else
  101.         return(TRUE);
  102. #endif
  103. }
  104.  
  105. PASCAL NEAR gotoline(f, n)    /* move to a particular line.
  106.                argument (n) must be a positive integer for
  107.                this to actually do anything        */
  108.  
  109. int f,n;    /* prefix flag and argument */
  110.  
  111. {
  112.     register int status;    /* status return */
  113.     char arg[NSTRING];    /* buffer to hold argument */
  114.  
  115.     /* get an argument if one doesnt exist */
  116.     if (f == FALSE) {
  117.         if ((status = mlreply(TEXT7, arg, NSTRING)) != TRUE) {
  118. /*                                    "Line to GOTO: " */
  119.             mlwrite(TEXT8);
  120. /*                              "[Aborted]" */
  121.             return(status);
  122.         }
  123.         n = asc_int(arg);
  124.     }
  125.  
  126.     if (n < 1)        /* if a bogus argument...then leave */
  127.         return(FALSE);
  128.  
  129.     /* first, we go to the start of the buffer */
  130.         curwp->w_dotp  = lforw(curbp->b_linep);
  131.         curwp->w_doto  = 0;
  132.     return(forwline(f, n-1));
  133. }
  134.  
  135. /*
  136.  * Goto the beginning of the buffer. Massive adjustment of dot. This is
  137.  * considered to be hard motion; it really isn't if the original value of dot
  138.  * is the same as the new value of dot. Normally bound to "M-<".
  139.  */
  140. PASCAL NEAR gotobob(f, n)
  141.  
  142. int f,n;    /* argument flag and num */
  143.  
  144. {
  145.         curwp->w_dotp  = lforw(curbp->b_linep);
  146.         curwp->w_doto  = 0;
  147.         curwp->w_flag |= WFMOVE;
  148.         return(TRUE);
  149. }
  150.  
  151. /*
  152.  * Move to the end of the buffer. Dot is always put at the end of the file
  153.  * (ZJ). The standard screen code does most of the hard parts of update.
  154.  * Bound to "M->".
  155.  */
  156. PASCAL NEAR gotoeob(f, n)
  157.  
  158. int f,n;    /* argument flag and num */
  159.  
  160. {
  161.         curwp->w_dotp  = curbp->b_linep;
  162.         curwp->w_doto  = 0;
  163.         curwp->w_flag |= WFMOVE;
  164.         return(TRUE);
  165. }
  166.  
  167. /*
  168.  * Move forward by full lines. If the number of lines to move is less than
  169.  * zero, call the backward line function to actually do it. The last command
  170.  * controls how the goal column is set. Bound to "C-N". No errors are
  171.  * possible.
  172.  */
  173. PASCAL NEAR forwline(f, n)
  174.  
  175. int f,n;    /* argument flag and num */
  176.  
  177. {
  178.         register LINE   *dlp;
  179.  
  180.         if (n < 0)
  181.                 return(backline(f, -n));
  182.  
  183.     /* if we are on the last line as we start....fail the command */
  184.     if (curwp->w_dotp == curbp->b_linep)
  185.         return(FALSE);
  186.  
  187.     /* if the last command was not note a line move,
  188.        reset the goal column */
  189.         if ((lastflag&CFCPCN) == 0)
  190.                 curgoal = getccol(FALSE);
  191.  
  192.     /* flag this command as a line move */
  193.         thisflag |= CFCPCN;
  194.  
  195.     /* and move the point down */
  196.         dlp = curwp->w_dotp;
  197.         while (n-- && dlp!=curbp->b_linep)
  198.                 dlp = lforw(dlp);
  199.  
  200.     /* reseting the current position */
  201.         curwp->w_dotp  = dlp;
  202.         curwp->w_doto  = getgoal(dlp);
  203.         curwp->w_flag |= WFMOVE;
  204. #if    DBCS
  205.     return(stopback());
  206. #else
  207.         return(TRUE);
  208. #endif
  209. }
  210.  
  211. /*
  212.  * This function is like "forwline", but goes backwards. The scheme is exactly
  213.  * the same. Check for arguments that are less than zero and call your
  214.  * alternate. Figure out the new line and call "movedot" to perform the
  215.  * motion. No errors are possible. Bound to "C-P".
  216.  */
  217. PASCAL NEAR backline(f, n)
  218.  
  219. int f,n;    /* argument flag and num */
  220.  
  221. {
  222.         register LINE   *dlp;
  223.  
  224.         if (n < 0)
  225.                 return(forwline(f, -n));
  226.  
  227.  
  228.     /* if we are on the last line as we start....fail the command */
  229.     if (lback(curwp->w_dotp) == curbp->b_linep)
  230.         return(FALSE);
  231.  
  232.     /* if the last command was not note a line move,
  233.        reset the goal column */
  234.         if ((lastflag&CFCPCN) == 0)
  235.                 curgoal = getccol(FALSE);
  236.  
  237.     /* flag this command as a line move */
  238.         thisflag |= CFCPCN;
  239.  
  240.     /* and move the point up */
  241.         dlp = curwp->w_dotp;
  242.         while (n-- && lback(dlp)!=curbp->b_linep)
  243.                 dlp = lback(dlp);
  244.  
  245.     /* reseting the current position */
  246.         curwp->w_dotp  = dlp;
  247.         curwp->w_doto  = getgoal(dlp);
  248.         curwp->w_flag |= WFMOVE;
  249. #if    DBCS
  250.     return(stopback());
  251. #else
  252.         return(TRUE);
  253. #endif
  254. }
  255.  
  256. PASCAL NEAR gotobop(f, n) /* go back to the beginning of the current paragraph
  257.            here we look for a blank line or a character from
  258.            $paralead to delimit the beginning of a paragraph or
  259.            $fmtlead to delimit a line before the paragraph */
  260.  
  261. int f, n;    /* default Flag & Numeric argument */
  262.  
  263. {
  264.     register int suc;    /* success of last backchar */
  265.     register int c;        /* current character in scan */
  266.     register char *sp;    /* ptr into character leadin lists */
  267.  
  268.     if (n < 0)    /* the other way...*/
  269.         return(gotoeop(f, -n));
  270.  
  271.     while (n-- > 0) {    /* for each one asked for */
  272.  
  273.         /* first scan back until we are in a word */
  274.         suc = backchar(FALSE, 1);
  275.         while (!inword() && suc)
  276.             suc = backchar(FALSE, 1);
  277.         curwp->w_doto = 0;    /* and go to the B-O-Line */
  278.  
  279.         /* scan back through the text */
  280.         while (lback(curwp->w_dotp) != curbp->b_linep) {
  281.  
  282.             /* at blank line */
  283.             if (lused(curwp->w_dotp) == 0)
  284.                 break;
  285.  
  286.             /* current line start with member of $paralead? */
  287.             c = lgetc(curwp->w_dotp, 0);
  288.             sp = paralead;
  289.             while (*sp) {
  290.                 if (c == *sp)
  291.                     break;
  292.                 ++sp;
  293.             }
  294.             if (c == *sp)
  295.                 break;            
  296.  
  297.             /* last line start with member of $fmtlead? */
  298.             c = lgetc(lback(curwp->w_dotp), 0);
  299.             sp = fmtlead;
  300.             while (*sp) {
  301.                 if (c == *sp)
  302.                     break;
  303.                 ++sp;
  304.             }
  305.             if (c == *sp)
  306.                 break;            
  307.  
  308.             /* back one line... */
  309.             curwp->w_dotp = lback(curwp->w_dotp);
  310.         }
  311.  
  312.         /* and then forward until we are in a word */
  313. /*        suc = forwchar(FALSE, 1); */
  314.         suc = TRUE;
  315.         while (suc && !inword())
  316.             suc = forwchar(FALSE, 1);
  317.     }
  318.     curwp->w_flag |= WFMOVE;    /* force screen update */
  319.     return(TRUE);
  320. }
  321.  
  322. PASCAL NEAR gotoeop(f, n) /* go forword to the end of the current paragraph
  323.                  looking for a member of $paralead or $fmtlead
  324.                  or a blank line to delimit the start of the
  325.                  next paragraph
  326. */
  327.  
  328. int f, n;    /* default Flag & Numeric argument */
  329.  
  330. {
  331.     register int suc;    /* success of last backchar */
  332.     register int c;        /* current character in scan */
  333.     register char *sp;    /* ptr into character leadin lists */
  334.  
  335.     if (n < 0)    /* the other way...*/
  336.         return(gotobop(f, -n));
  337.  
  338.     while (n-- > 0) {    /* for each one asked for */
  339.  
  340.         /* first scan forward until we are in a word */
  341.         suc = forwchar(FALSE, 1);
  342.         while (!inword() && suc)
  343.             suc = forwchar(FALSE, 1);
  344.  
  345.         /* and go to the B-O-Line */
  346.         curwp->w_doto = 0;
  347.  
  348.         /* of next line if not at EOF */
  349.         if (suc)
  350.             curwp->w_dotp = lforw(curwp->w_dotp);
  351.  
  352.         /* scan forward */
  353.         while (curwp->w_dotp != curbp->b_linep) {
  354.  
  355.             /* at blank line */
  356.             if (lused(curwp->w_dotp) == 0)
  357.                 break;
  358.  
  359.             /* current line start with member of $paralead? */
  360.             c = lgetc(curwp->w_dotp, 0);
  361.             sp = paralead;
  362.             while (*sp) {
  363.                 if (c == *sp)
  364.                     break;
  365.                 ++sp;
  366.             }
  367.             if (c == *sp)
  368.                 break;            
  369.  
  370.             /* current line start with member of $fmtlead? */
  371.             c = lgetc(curwp->w_dotp, 0);
  372.             sp = fmtlead;
  373.             while (*sp) {
  374.                 if (c == *sp)
  375.                     break;
  376.                 ++sp;
  377.             }
  378.             if (c == *sp)
  379.                 break;            
  380.  
  381.             /* forward one line... */
  382.             curwp->w_dotp = lforw(curwp->w_dotp);
  383.         }
  384.  
  385.         /* and then backward until we are in a word */
  386.         suc = backchar(FALSE, 1);
  387.         while (suc && !inword()) {
  388.             suc = backchar(FALSE, 1);
  389.         }
  390.         curwp->w_doto = lused(curwp->w_dotp);    /* and to the EOL */
  391.     }
  392.     curwp->w_flag |= WFMOVE;    /* force screen update */
  393.     return(TRUE);
  394. }
  395.  
  396. /*
  397.  * This routine, given a pointer to a LINE, and the current cursor goal
  398.  * column, return the best choice for the offset. The offset is returned.
  399.  * Used by "C-N" and "C-P".
  400.  */
  401.  
  402. int PASCAL NEAR getgoal(dlp)
  403.  
  404. register LINE   *dlp;
  405.  
  406. {
  407.         register int    c;
  408.         register int    col;
  409.         register int    newcol;
  410.         register int    dbo;
  411.  
  412.         col = 0;
  413.         dbo = 0;
  414.         while (dbo != lused(dlp)) {
  415.                 c = lgetc(dlp, dbo);
  416.                 newcol = col;
  417.                 if (c == '\t' && tabsize > 0)
  418.             newcol += -(newcol % tabsize) + (tabsize - 1);
  419.                 else if (c<0x20 || c==0x7F)
  420.                         ++newcol;
  421.                 ++newcol;
  422.                 if (newcol > curgoal)
  423.                         break;
  424.                 col = newcol;
  425.                 ++dbo;
  426.         }
  427.         return(dbo);
  428. }
  429.  
  430. /*
  431.  * Scroll forward by a specified number of lines, or by a full page if no
  432.  * argument. Bound to "C-V". The overlap in the arithmetic on the window size
  433.  * is overlap between screens. This defaults to overlap value in ITS EMACS.
  434.  *  Because this zaps the top line in the window, we have to do a hard update.
  435.  */
  436. PASCAL NEAR forwpage(f, n)
  437.  
  438. int f,n;    /* prefix flag and argument */
  439.  
  440. {
  441.         register LINE   *lp;
  442.  
  443.     /*
  444.      * Calculate the lines to scroll, taking into account
  445.      * the $overlap count and whether the modeline is on or not.
  446.      */
  447.         if (f == FALSE) {
  448.                 n = curwp->w_ntrows - overlap + !modeflag;        /* Default scroll.      */
  449.                 if (n <= 0)                     /* Forget the overlap   */
  450.                         n = 1;                  /* if tiny window.      */
  451.         } else if (n < 0)
  452.                 return(backpage(f, -n));
  453.         lp = curwp->w_linep;
  454.         while (n-- && lp!=curbp->b_linep)
  455.                 lp = lforw(lp);
  456.         curwp->w_linep = lp;
  457.         curwp->w_dotp  = lp;
  458.         curwp->w_doto  = 0;
  459.         curwp->w_flag |= WFHARD;
  460.         return(TRUE);
  461. }
  462.  
  463. /*
  464.  * This command is like "forwpage", but it goes backwards. overlap, like
  465.  * above, is the overlap between the two windows. The value is from the ITS
  466.  * EMACS manual. Bound to "M-V". We do a hard update for exactly the same
  467.  * reason.
  468.  */
  469. PASCAL NEAR backpage(f, n)
  470.  
  471. register int f;
  472. register int n;
  473.  
  474. {
  475.         register LINE   *lp;
  476.  
  477.     /*
  478.      * Calculate the lines to scroll, taking into account
  479.      * the $overlap count and whether the modeline is on or not.
  480.      */
  481.         if (f == FALSE) {
  482.                 n = curwp->w_ntrows - overlap + !modeflag;        /* Default scroll.      */
  483.                 if (n <= 0)                     /* Don't blow up if the */
  484.                         n = 1;                  /* window is tiny.      */
  485.         } else if (n < 0)
  486.                 return(forwpage(f, -n));
  487.         lp = curwp->w_linep;
  488.         while (n-- && lback(lp)!=curbp->b_linep)
  489.                 lp = lback(lp);
  490.         curwp->w_linep = lp;
  491.         curwp->w_dotp  = lp;
  492.         curwp->w_doto  = 0;
  493.         curwp->w_flag |= WFHARD;
  494.         return(TRUE);
  495. }
  496.  
  497. /*
  498.  * Set the mark in the current window to the value of "." in the window. No
  499.  * errors are possible. Bound to "M-.".
  500.  */
  501. PASCAL NEAR setmark(f, n)
  502.  
  503. int f,n;    /* argument flag and num */
  504.  
  505. {
  506.     /* make sure it is in range */
  507.     if (f == FALSE)
  508.         n = 0;
  509.     n %= NMARKS;
  510.  
  511.         curwp->w_markp[n] = curwp->w_dotp;
  512.         curwp->w_marko[n] = curwp->w_doto;
  513.         mlwrite(TEXT9, n);
  514. /*              "[Mark %d set]" */
  515.         return(TRUE);
  516. }
  517.  
  518. /*
  519.  * Remove the mark in the current window.
  520.  * Bound to ^X <space> 
  521.  */
  522. PASCAL NEAR remmark(f, n)
  523.  
  524. int f,n;    /* argument flag and num */
  525.  
  526. {
  527.     /* make sure it is in range */
  528.     if (f == FALSE)
  529.         n = 0;
  530.     n %= NMARKS;
  531.  
  532.         curwp->w_markp[n] = NULL;
  533.         curwp->w_marko[n] = 0;
  534.         mlwrite(TEXT10, n);
  535. /*              "[Mark %d removed]" */
  536.         return(TRUE);
  537. }
  538.  
  539. /*
  540.  * Swap the values of "." and "mark" in the current window. This is pretty
  541.  * easy, bacause all of the hard work gets done by the standard routine
  542.  * that moves the mark about. The only possible error is "no mark". Bound to
  543.  * "C-X C-X".
  544.  */
  545. PASCAL NEAR swapmark(f, n)
  546.  
  547. int f,n;    /* argument flag and num */
  548.  
  549. {
  550.         register LINE   *odotp;
  551.         register int    odoto;
  552.  
  553.     /* make sure it is in range */
  554.     if (f == FALSE)
  555.         n = 0;
  556.     n %= NMARKS;
  557.  
  558.         if (curwp->w_markp[n] == NULL) {
  559.                 mlwrite(TEXT11, n);
  560. /*                      "No mark %d in this window" */
  561.                 return(FALSE);
  562.         }
  563.         odotp = curwp->w_dotp;
  564.         odoto = curwp->w_doto;
  565.         curwp->w_dotp  = curwp->w_markp[n];
  566.         curwp->w_doto  = curwp->w_marko[n];
  567.         curwp->w_markp[n] = odotp;
  568.         curwp->w_marko[n] = odoto;
  569.         curwp->w_flag |= WFMOVE;
  570.         return(TRUE);
  571. }
  572.  
  573. /*
  574.  * Goto a mark in the current window. This is pretty easy, bacause all of
  575.  * the hard work gets done by the standard routine that moves the mark
  576.  * about. The only possible error is "no mark". Bound to "M-^G".
  577.  */
  578. PASCAL NEAR gotomark(f, n)
  579.  
  580. int f, n;    /* default and numeric args */
  581.  
  582. {
  583.     /* make sure it is in range */
  584.     if (f == FALSE)
  585.         n = 0;
  586.     n %= NMARKS;
  587.  
  588.         if (curwp->w_markp[n] == NULL) {
  589.                 mlwrite(TEXT11, n);
  590. /*                      "No mark %d in this window" */
  591.                 return(FALSE);
  592.         }
  593.         curwp->w_dotp  = curwp->w_markp[n];
  594.         curwp->w_doto  = curwp->w_marko[n];
  595.         curwp->w_flag |= WFMOVE;
  596.         return(TRUE);
  597. }
  598.  
  599. #if    DBCS
  600. /* advance a char if we are on the second byte of a DBCS character */
  601.  
  602. int PASCAL NEAR stopforw()
  603.  
  604. {
  605.     /* don't stop on the second byte of a 2 byte character */
  606.     if (curwp->w_doto > 0 && is2byte(ltext(curwp->w_dotp),
  607.         ltext(curwp->w_dotp) + curwp->w_doto - 1))
  608.             return(forwchar(TRUE, 1));
  609.     return(TRUE);
  610. }
  611.  
  612. /* retreat a char if we are on the second byte of a DBCS character */
  613.  
  614. int PASCAL NEAR stopback()
  615.  
  616. {
  617.     /* don't stop on the second byte of a 2 byte character */
  618.     if (curwp->w_doto > 0 && is2byte(ltext(curwp->w_dotp),
  619.         ltext(curwp->w_dotp) + curwp->w_doto - 1))
  620.             return(backchar(TRUE, 1));
  621.     return(TRUE);
  622. }
  623. #endif
  624.  
  625.