home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / VILE327.ZIP / VILE327.TAR / vile3.27 / basic.c < prev    next >
C/C++ Source or Header  |  1992-12-14  |  29KB  |  1,212 lines

  1. /*
  2.  * The routines in this file move the cursor around on the screen. They
  3.  * compute a new value for the cursor, then adjust ".". The display code
  4.  * always updates the cursor location, so only moves between lines, or
  5.  * functions that adjust the top line in the window and invalidate the
  6.  * framing, are hard.
  7.  *
  8.  * $Log: basic.c,v $
  9.  * Revision 1.41  1992/12/05  13:12:16  foxharp
  10.  * fix paragraph problem -- i didn't fix all the firstchar() calls before
  11.  *
  12.  * Revision 1.40  1992/12/04  09:08:45  foxharp
  13.  * deleted unused assigns
  14.  *
  15.  * Revision 1.39  1992/11/30  23:06:03  foxharp
  16.  * firstchar/lastchar now return -1 for no non-white chars in line
  17.  *
  18.  * Revision 1.38  1992/08/20  23:40:48  foxharp
  19.  * typo fixes -- thanks, eric
  20.  *
  21.  * Revision 1.37  1992/08/04  20:09:03  foxharp
  22.  * prototype fixups, for xvile
  23.  *
  24.  * Revision 1.36  1992/05/16  12:00:31  pgf
  25.  * prototypes/ansi/void-int stuff/microsoftC
  26.  *
  27.  * Revision 1.35  1992/03/22  10:54:41  pgf
  28.  * fixed bad bug in gotoline
  29.  *
  30.  * Revision 1.34  1992/03/19  23:30:35  pgf
  31.  * gotoline can now take neg. argument, to count from bottom of
  32.  * buffer. (for finderr)
  33.  *
  34.  * Revision 1.33  1992/03/19  23:05:50  pgf
  35.  * forwpage now sets WFMODE
  36.  *
  37.  * Revision 1.32  1992/03/13  08:12:53  pgf
  38.  * new paragraph behavior wrt blank lines, once again
  39.  *
  40.  * Revision 1.31  1992/03/03  21:57:01  pgf
  41.  * fixed loop at buffer top/bottom in gotoeosent
  42.  *
  43.  * Revision 1.30  1992/02/17  08:49:47  pgf
  44.  * took out unused var for saber
  45.  *
  46.  * Revision 1.29  1992/01/22  17:15:25  pgf
  47.  * minor change to blank-line-skip for backward paragraph motions
  48.  *
  49.  * Revision 1.28  1992/01/22  16:58:20  pgf
  50.  * paragraph motions now treat consecutive blank lines as a single paragraph
  51.  * delimeter (note that this is independent of what the regexp says)
  52.  *
  53.  * Revision 1.27  1992/01/10  08:10:15  pgf
  54.  * don't bother with list mode in next_column(), since this should _always_
  55.  * give the "unlist-moded" column
  56.  *
  57.  * Revision 1.26  1992/01/05  00:06:13  pgf
  58.  * split mlwrite into mlwrite/mlprompt/mlforce to make errors visible more
  59.  * often.  also normalized message appearance somewhat.
  60.  *
  61.  * Revision 1.25  1992/01/03  23:35:47  pgf
  62.  * screen motions (goto[emb]os()) now unconditionally return TRUE, to
  63.  * eliminate oddness when buffer doesn't fill window
  64.  *
  65.  * paragraph and section motions no longer fail at the bottom of the
  66.  * buffer (operators wouldn't work)
  67.  *
  68.  * paragraph motions are treated more vi-like.  in particular, whether
  69.  * a para motion is character or line oriented is determined by where
  70.  * the motion starts and finishes.  thanks to Eric Krohn for this tip.
  71.  * (forward, the motion is line oriented if it moves off the current line
  72.  * and it started at the beginning of the line.  otherwise it's character
  73.  * oriented.  backward, it's similar, but it's line oriented if it starts
  74.  * at the beginning _or_ end of a line.)
  75.  *
  76.  * Revision 1.24  1991/12/24  18:32:28  pgf
  77.  * don't reset lastdot mark if we're moving to a mark and it's on behalf
  78.  * of an opcmd
  79.  *
  80.  * Revision 1.23  1991/11/13  20:09:27  pgf
  81.  * X11 changes, from dave lemke
  82.  *
  83.  * Revision 1.22  1991/11/10  22:28:17  pgf
  84.  * the goto{end,begin}of{para,sec,sentence} motions now return TRUE, whether
  85.  * they really went to a para,sec, or sentence, or went to the beginning or
  86.  * end of the buffer because there were no more paras, secs, or sentences.
  87.  * this makes operators work right.
  88.  *
  89.  * Revision 1.21  1991/11/08  13:08:04  pgf
  90.  * moved firstchar() here, created lastchar(), and
  91.  * eliminated unused atmark()
  92.  *
  93.  * Revision 1.20  1991/11/03  17:33:20  pgf
  94.  * use new lregexec() routine to check for patterns in lines
  95.  *
  96.  * Revision 1.19  1991/11/01  14:38:00  pgf
  97.  * saber cleanup
  98.  *
  99.  * Revision 1.18  1991/11/01  14:10:35  pgf
  100.  * matchlen is now part of a regexp, not global
  101.  *
  102.  * Revision 1.17  1991/10/28  00:57:31  pgf
  103.  * cleaned the sentence motions some more
  104.  *
  105.  * Revision 1.16  1991/10/27  16:09:06  pgf
  106.  * improved the sentence motions
  107.  *
  108.  * Revision 1.15  1991/10/26  00:12:34  pgf
  109.  * section, paragraph, and new sentence motions are all regex based
  110.  *
  111.  * Revision 1.14  1991/09/27  02:48:16  pgf
  112.  * remove unused automatics
  113.  *
  114.  * Revision 1.13  1991/09/26  13:05:45  pgf
  115.  * undid forw/backline optimization, since it causes flags to not be set,
  116.  * and moved LIST mode to window
  117.  *
  118.  * Revision 1.12  1991/09/24  01:04:33  pgf
  119.  * forwline and backline now do nothing if passed 0 arg
  120.  *
  121.  * Revision 1.11  1991/09/19  12:22:57  pgf
  122.  * paragraphs now end at nroff-style section boundaries as well
  123.  *
  124.  * Revision 1.10  1991/08/07  12:35:07  pgf
  125.  * added RCS log messages
  126.  *
  127.  * revision 1.9
  128.  * date: 1991/08/06 15:10:26;
  129.  * bug fix in forwline, and
  130.  * global/local values
  131.  * 
  132.  * revision 1.8
  133.  * date: 1991/06/25 19:52:01;
  134.  * massive data structure restructure
  135.  * 
  136.  * revision 1.7
  137.  * date: 1991/06/20 17:22:42;
  138.  * fixed write-to-const-string problem in setnmmark
  139.  * 
  140.  * revision 1.6
  141.  * date: 1991/06/16 17:33:32;
  142.  * added next_column() routine, along with converting to modulo tab processing
  143.  * 
  144.  * revision 1.5
  145.  * date: 1991/06/15 09:08:44;
  146.  * added new forwchar_to_eol, and backchar_to_bol
  147.  * 
  148.  * revision 1.4
  149.  * date: 1991/06/03 10:17:45;
  150.  * prompt for mark name in setnmmark if isnamedcmd
  151.  * 
  152.  * revision 1.3
  153.  * date: 1991/05/31 10:29:06;
  154.  * fixed "last dot" mark code, and
  155.  * added godotplus() for the operators
  156.  * 
  157.  * revision 1.2
  158.  * date: 1990/09/25 11:37:50;
  159.  * took out old ifdef BEFORE code
  160.  * 
  161.  * revision 1.1
  162.  * date: 1990/09/21 10:24:42;
  163.  * initial vile RCS revision
  164.  */
  165. #include        <stdio.h>
  166. #include    "estruct.h"
  167. #include        "edef.h"
  168.  
  169. /*
  170.  * Move the cursor to the
  171.  * beginning of the current line.
  172.  * Trivial.
  173.  */
  174. /* ARGSUSED */
  175. int
  176. gotobol(f, n)
  177. int f,n;
  178. {
  179.         curwp->w_dot.o  = 0;
  180.         return (TRUE);
  181. }
  182.  
  183. /*
  184.  * Move the cursor backwards by "n" characters. If "n" is less than zero call
  185.  * "forwchar" to actually do the move. Otherwise compute the new cursor
  186.  * location. Error if you try and move out of the buffer. Set the flag if the
  187.  * line pointer for dot changes.
  188.  */
  189. int
  190. backchar(f, n)
  191. int f;
  192. register int n;
  193. {
  194.         register LINE   *lp;
  195.  
  196.     if (f == FALSE) n = 1;
  197.         if (n < 0)
  198.                 return (forwchar(f, -n));
  199.         while (n--) {
  200.                 if (curwp->w_dot.o == 0) {
  201.                         if ((lp=lback(curwp->w_dot.l)) == curbp->b_line.l)
  202.                                 return (FALSE);
  203.                         curwp->w_dot.l  = lp;
  204.                         curwp->w_dot.o  = llength(lp);
  205.                         curwp->w_flag |= WFMOVE;
  206.                 } else
  207.                         curwp->w_dot.o--;
  208.         }
  209.         return (TRUE);
  210. }
  211.  
  212. /*
  213.  * Move the cursor backwards by "n" characters. Stop at beginning of line.
  214.  */
  215. int
  216. backchar_to_bol(f, n)
  217. int f;
  218. register int    n;
  219. {
  220.  
  221.     if (f == FALSE) n = 1;
  222.         if (n < 0)
  223.                 return forwchar_to_eol(f, -n);
  224.         while (n--) {
  225.                 if (curwp->w_dot.o == 0)
  226.             return TRUE;
  227.                 else
  228.                         curwp->w_dot.o--;
  229.         }
  230.         return TRUE;
  231. }
  232.  
  233. /*
  234.  * Move the cursor to the end of the current line. Trivial. No errors.
  235.  */
  236. int
  237. gotoeol(f, n)
  238. int f,n;
  239. {
  240.     if (f == TRUE) {
  241.         if (n > 0)
  242.              --n;
  243.         else if (n < 0)
  244.              ++n;
  245.         forwline(f,n);
  246.     }
  247.         curwp->w_dot.o  = llength(curwp->w_dot.l);
  248.     curgoal = HUGE;
  249.         return (TRUE);
  250. }
  251.  
  252. /*
  253.  * Move the cursor forwards by "n" characters. If "n" is less than zero call
  254.  * "backchar" to actually do the move. Otherwise compute the new cursor
  255.  * location, and move ".". Error if you try and move off the end of the
  256.  * buffer. Set the flag if the line pointer for dot changes.
  257.  */
  258. int
  259. forwchar(f, n)
  260. int f;
  261. register int    n;
  262. {
  263.     if (f == FALSE) n = 1;
  264.         if (n < 0)
  265.                 return (backchar(f, -n));
  266.         while (n--) {
  267.                 if (is_at_end_of_line(curwp->w_dot)) {
  268.                         if (is_header_line(curwp->w_dot, curbp) ||
  269.                     is_last_line(curwp->w_dot,curbp))
  270.                                 return (FALSE);
  271.                         curwp->w_dot.l  = lforw(curwp->w_dot.l);
  272.                         curwp->w_dot.o  = 0;
  273.                         curwp->w_flag |= WFMOVE;
  274.                 } else
  275.                         curwp->w_dot.o++;
  276.         }
  277.         return (TRUE);
  278. }
  279.  
  280. /*
  281.  * Move the cursor forwards by "n" characters. Don't go past end-of-line
  282.  */
  283. int
  284. forwchar_to_eol(f, n)
  285. int f;
  286. register int    n;
  287. {
  288.     if (f == FALSE) n = 1;
  289.         if (n < 0)
  290.                 return backchar_to_bol(f, -n);
  291.         while (n--) {
  292.                 if (is_at_end_of_line(curwp->w_dot))
  293.             return TRUE;
  294.                 else
  295.                         curwp->w_dot.o++;
  296.         }
  297.         return TRUE;
  298. }
  299.  
  300. /* move to a particular line. */
  301. /* count from bottom of file if negative */
  302. int
  303. gotoline(f, n)
  304. int f,n;
  305. {
  306.     register int status;    /* status return */
  307.  
  308.     /* get an argument if one doesnt exist */
  309.     if (f == FALSE) {
  310.         return(gotoeob(f,n));
  311.     }
  312.  
  313.     if (n == 0)        /* if a bogus argument...then leave */
  314.         return(FALSE);
  315.  
  316.     curwp->w_dot.o  = 0;
  317.     if (n < 0) {
  318.         curwp->w_dot.l  = lback(curbp->b_line.l);
  319.         status = backline(f, -n - 1 );
  320.     } else {
  321.         curwp->w_dot.l  = lforw(curbp->b_line.l);
  322.         status = forwline(f, n-1);
  323.     }
  324.     if (status == TRUE)
  325.         firstnonwhite(f,n);
  326.     return(status);
  327. }
  328.  
  329. /*
  330.  * Goto the beginning of the buffer. Massive adjustment of dot. This is
  331.  * considered to be hard motion; it really isn't if the original value of dot
  332.  * is the same as the new value of dot.
  333.  */
  334. /* ARGSUSED */
  335. int
  336. gotobob(f, n)
  337. int f,n;
  338. {
  339.         curwp->w_dot.l  = lforw(curbp->b_line.l);
  340.         curwp->w_dot.o  = 0;
  341.         curwp->w_flag |= WFMOVE;
  342.         return (TRUE);
  343. }
  344.  
  345. /*
  346.  * Move to the end of the buffer. Dot is always put at the end of the file.
  347.  */
  348. /* ARGSUSED */
  349. int
  350. gotoeob(f, n)
  351. int f,n;
  352. {
  353.         curwp->w_dot.l  = lback(curbp->b_line.l);
  354.     firstnonwhite(FALSE,1);
  355.         curwp->w_flag |= WFMOVE;
  356.         return TRUE;
  357. }
  358.  
  359. int
  360. gotobos(f,n)
  361. int f,n;
  362. {
  363.     if (f == FALSE || n <= 0) n = 1;
  364.     curwp->w_dot.l = curwp->w_line.l;
  365.     while (--n) {
  366.         if (forwline(FALSE,1) != TRUE)
  367.             break;
  368.     }
  369.     firstnonwhite(f,n);
  370.     return TRUE;
  371. }
  372.  
  373. /* ARGSUSED */
  374. int
  375. gotomos(f,n)
  376. int f,n;
  377. {
  378.     return gotobos(TRUE,curwp->w_ntrows/2);
  379. }
  380.  
  381. int
  382. gotoeos(f,n)
  383. int f,n;
  384. {
  385.     return gotobos(TRUE,curwp->w_ntrows-(f==TRUE? n-1:0));
  386. }
  387.  
  388. /*
  389.  * Move forward by full lines. If the number of lines to move is less than
  390.  * zero, call the backward line function to actually do it. The last command
  391.  * controls how the goal column is set. No errors are
  392.  * possible.
  393.  */
  394. int
  395. forwline(f, n)
  396. int f,n;
  397. {
  398.         register LINE   *dlp;
  399.  
  400.     if (f == FALSE) n = 1;
  401.         if (n < 0)
  402.                 return (backline(f, -n));
  403.  
  404.     /* if we are on the last line as we start....fail the command */
  405.     if (is_last_line(curwp->w_dot, curbp))
  406.         return(FALSE);
  407.  
  408.     /* if the last command was not a line move,
  409.        reset the goal column */
  410.         if (curgoal < 0)
  411.                 curgoal = getccol(FALSE);
  412.  
  413.     /* and move the point down */
  414.         dlp = curwp->w_dot.l;
  415.         while (n-- && dlp!=curbp->b_line.l)
  416.                 dlp = lforw(dlp);
  417.  
  418.     /* resetting the current position */
  419.         curwp->w_dot.l  = (dlp == curbp->b_line.l) ? lback(dlp) : dlp;
  420.         curwp->w_dot.o  = getgoal(dlp);
  421.         curwp->w_flag |= WFMOVE;
  422.         return (TRUE);
  423. }
  424.  
  425. /* ARGSUSED */
  426. int
  427. firstnonwhite(f,n)
  428. int f,n;
  429. {
  430.         DOT.o  = firstchar(DOT.l);
  431.     if (DOT.o < 0) {
  432.         if (llength(DOT.l) == 0)
  433.             DOT.o = 0;
  434.         else
  435.             DOT.o = llength(DOT.l) - 1;
  436.     }
  437.     return TRUE;
  438. }
  439.  
  440. /* ARGSUSED */
  441. int
  442. lastnonwhite(f,n)
  443. int f,n;
  444. {
  445.         DOT.o  = lastchar(DOT.l);
  446.     if (DOT.o < 0)
  447.         DOT.o = 0;
  448.     return TRUE;
  449. }
  450.  
  451. /* return the offset of the first non-white character on the line,
  452.     or -1 if there are no non-white characters on the line */
  453. int
  454. firstchar(lp)
  455. LINE *lp;
  456. {
  457.     int off = 0;
  458.     while ( off != llength(lp) && isspace(lgetc(lp, off)) )
  459.         off++;
  460.     if (off == llength(lp))
  461.         return -1;
  462.     return off;
  463. }
  464.  
  465. /* return the offset of the last non-white character on the line
  466.     or -1 if there are no non-white characters on the line */
  467. int
  468. lastchar(lp)
  469. LINE *lp;
  470. {
  471.     int off = llength(lp)-1;
  472.     while ( off >= 0 && isspace(lgetc(lp, off)) )
  473.         off--;
  474.     return off;
  475. }
  476.  
  477. /* like forwline, but got to first non-white char position */
  478. int
  479. forwbline(f,n)
  480. int f,n;
  481. {
  482.     int s;
  483.  
  484.     if (f == FALSE) n = 1;
  485.     if ((s = forwline(f,n)) != TRUE)
  486.         return (s);
  487.     firstnonwhite(f,n);
  488.     return(TRUE);
  489. }
  490.  
  491. /* like backline, but got to first non-white char position */
  492. int
  493. backbline(f,n)
  494. int f,n;
  495. {
  496.     int s;
  497.  
  498.     if (f == FALSE) n = 1;
  499.     if ((s = backline(f,n)) != TRUE)
  500.         return (s);
  501.     firstnonwhite(f,n);
  502.     return(TRUE);
  503. }
  504.  
  505. /*
  506.  * This function is like "forwline", but goes backwards. The scheme is exactly
  507.  * the same. Check for arguments that are less than zero and call your
  508.  * alternate. Figure out the new line and call "movedot" to perform the
  509.  * motion. No errors are possible.
  510.  */
  511. int
  512. backline(f, n)
  513. int f,n;
  514. {
  515.         register LINE   *dlp;
  516.  
  517.     if (f == FALSE) n = 1;
  518.         if (n < 0)
  519.                 return (forwline(f, -n));
  520.  
  521.     /* if we are on the first line as we start....fail the command */
  522.     if (is_first_line(curwp->w_dot, curbp))
  523.         return(FALSE);
  524.  
  525.     /* if the last command was not note a line move,
  526.        reset the goal column */
  527.         if (curgoal < 0)
  528.                 curgoal = getccol(FALSE);
  529.  
  530.     /* and move the point up */
  531.         dlp = curwp->w_dot.l;
  532.         while (n-- && lback(dlp) != curbp->b_line.l)
  533.                 dlp = lback(dlp);
  534.  
  535.     /* reseting the current position */
  536.         curwp->w_dot.l  = dlp;
  537.         curwp->w_dot.o  = getgoal(dlp);
  538.         curwp->w_flag |= WFMOVE;
  539.         return (TRUE);
  540. }
  541.  
  542. #if    WORDPRO
  543.  
  544.  
  545. int
  546. gotobop(f,n)
  547. int f,n;
  548. {
  549.     MARK odot;
  550.     int was_on_empty;
  551.     int fc;
  552.  
  553.     if (!f) n = 1;
  554.  
  555.     was_on_empty = (llength(DOT.l) == 0);
  556.     odot = DOT;
  557.  
  558.     fc = firstchar(DOT.l);
  559.     if (doingopcmd && 
  560.         ((fc >= 0 && DOT.o <= fc) || fc < 0) && 
  561.         !is_first_line(DOT,curbp)) {
  562.         backchar(TRUE,DOT.o+1);
  563.         pre_op_dot = DOT;
  564.     }
  565.         while (n) {
  566.         if (findpat(TRUE, 1, b_val_rexp(curbp,VAL_PARAGRAPHS)->reg,
  567.                             REVERSE) != TRUE) {
  568.             gotobob(f,n);
  569.         } else if (llength(DOT.l) == 0) {
  570.             /* special case -- if we found an empty line,
  571.                 and it's adjacent to where we started,
  572.                 skip all adjacent empty lines, and try again */
  573.             if ( (was_on_empty && lforw(DOT.l) == odot.l) ||
  574.                 (n > 0 && llength(lforw(DOT.l)) == 0) ) {
  575.                 /* then we haven't really found what we
  576.                     wanted.  keep going */
  577.                 skipblanksb();
  578.                 continue;
  579.             }
  580.         }
  581.         n--;
  582.     }
  583.     if (doingopcmd) {
  584.         fc = firstchar(DOT.l);
  585.         if (!sameline(DOT,odot) && 
  586.             (pre_op_dot.o > lastchar(pre_op_dot.l)) &&
  587.             ((fc >= 0 && DOT.o <= fc) || fc < 0)) {
  588.             fulllineregions = TRUE;
  589.         }
  590.     }
  591.     return TRUE;
  592. }
  593.  
  594. int
  595. gotoeop(f,n)
  596. int f,n;
  597. {
  598.     MARK odot;
  599.     int was_at_bol;
  600.     int was_on_empty;
  601.     int fc;
  602.  
  603.     if (!f) n = 1;
  604.  
  605.     fc = firstchar(DOT.l);
  606.     was_on_empty = (llength(DOT.l) == 0);
  607.     was_at_bol = ((fc >= 0 && DOT.o <= fc) || fc < 0);
  608.     odot = DOT;
  609.  
  610.     while (n) {
  611.         if (findpat(TRUE, 1, b_val_rexp(curbp,VAL_PARAGRAPHS)->reg, 
  612.                         FORWARD) != TRUE) {
  613.             DOT = curbp->b_line;
  614.         } else if (llength(DOT.l) == 0) {
  615.             /* special case -- if we found an empty line. */
  616.             /* either as the very next line, or at the end of
  617.                 our search */
  618.             if ( (was_on_empty && lback(DOT.l) == odot.l) ||
  619.                 (n > 0 && llength(lback(DOT.l)) == 0) ) {
  620.                 /* then we haven't really found what we
  621.                     wanted.  keep going */
  622.                 skipblanksf();
  623.                 continue;
  624.             }
  625.         }
  626.         n--;
  627.     }
  628.     if (doingopcmd) {
  629.         /* if we're now at the beginning of a line and we can back up,
  630.           do so to avoid eating the newline and leading whitespace */
  631.         fc = firstchar(DOT.l);
  632.         if (((fc >= 0 && DOT.o <= fc) || fc < 0) && 
  633.             !is_first_line(DOT,curbp) &&
  634.             !sameline(DOT,odot) ) {
  635.             backchar(TRUE,DOT.o+1);
  636.         }
  637.         /* if we started at the start of line, eat the whole line */
  638.         if (!sameline(DOT,odot) && was_at_bol)
  639.             fulllineregions = TRUE;
  640.     }
  641.     return TRUE;
  642. }
  643.  
  644. void
  645. skipblanksf()
  646. {
  647.     while (lforw(DOT.l) != curbp->b_line.l && llength(DOT.l) == 0)
  648.         DOT.l = lforw(DOT.l);
  649. }
  650.  
  651. void
  652. skipblanksb()
  653. {
  654.     while (lback(DOT.l) != curbp->b_line.l && llength(DOT.l) == 0)
  655.         DOT.l = lback(DOT.l);
  656. }
  657.  
  658. #if STUTTER_SEC_CMD
  659. getstutter()
  660. {
  661.     int this1key;
  662.     if (!clexec) {
  663.         this1key = last1key;
  664.         kbd_seq();
  665.         if (this1key != last1key) {
  666.             TTbeep();
  667.             return FALSE;
  668.         }
  669.     }
  670.     return TRUE;
  671. }
  672. #endif
  673.  
  674. int
  675. gotobosec(f,n)
  676. int f,n;
  677. {
  678. #if STUTTER_SEC_CMD
  679.     if (!getstutter())
  680.         return FALSE;
  681. #endif
  682.     if (findpat(f, n, b_val_rexp(curbp,VAL_SECTIONS)->reg,
  683.                             REVERSE) != TRUE) {
  684.         gotobob(f,n);
  685.     }
  686.     return TRUE;
  687. }
  688.  
  689. int
  690. gotoeosec(f,n)
  691. int f,n;
  692. {
  693. #if STUTTER_SEC_CMD
  694.     if (!getstutter())
  695.         return FALSE;
  696. #endif
  697.     if (findpat(f, n, b_val_rexp(curbp,VAL_SECTIONS)->reg,
  698.                             FORWARD) != TRUE) {
  699.         DOT = curbp->b_line;
  700.     }
  701.     return TRUE;
  702. }
  703.  
  704. int
  705. gotobosent(f,n)
  706. int f,n;
  707. {
  708.     MARK savepos;
  709.     int looped = 0;
  710.     int extra;
  711.     register regexp *exp;
  712.     register int s;
  713.  
  714.     savepos = DOT;
  715.     exp = b_val_rexp(curbp,VAL_SENTENCES)->reg;
  716.  top:
  717.     extra = 0;
  718.     if (findpat(f, n, exp, REVERSE) != TRUE) {
  719.         gotobob(f,n);
  720.         return TRUE;
  721.     }
  722.     forwchar(TRUE, exp->mlen?exp->mlen:1);
  723.     while (is_at_end_of_line(DOT) || isspace(char_at(DOT))) {
  724.         forwchar(TRUE,1);
  725.         extra++;
  726.     }
  727.     if (n == 1 && samepoint(savepos,DOT)) { /* try again */
  728.         if (looped > 10)
  729.             return FALSE;
  730.         s = backchar(TRUE, (exp->mlen?exp->mlen:1) + extra + looped);
  731.         while (s && is_at_end_of_line(DOT))
  732.             s = backchar(TRUE,1);
  733.         looped++;
  734.         goto top;
  735.  
  736.     }
  737.     return TRUE;
  738. }
  739.  
  740. int
  741. gotoeosent(f,n)
  742. int f,n;
  743. {
  744.     register regexp *exp;
  745.     register int s;
  746.  
  747.     exp = b_val_rexp(curbp,VAL_SENTENCES)->reg;
  748.     /* if we're on the end of a sentence now, don't bother scanning
  749.         further, or we'll miss the immediately following sentence */
  750.     if (!(lregexec(exp, DOT.l, DOT.o, llength(DOT.l)) &&
  751.                 exp->startp[0] - DOT.l->l_text == DOT.o)) {
  752.         if (findpat(f, n, exp, FORWARD) != TRUE) {
  753.             DOT = curbp->b_line;
  754.             return TRUE;
  755.         }
  756.     }
  757.     s = forwchar(TRUE, exp->mlen?exp->mlen:1);
  758.     while (s && (is_at_end_of_line(DOT) || isspace(char_at(DOT)))) {
  759.         s = forwchar(TRUE,1);
  760.     }
  761.     return TRUE;
  762. }
  763.  
  764. #endif /* WORDPRO */
  765.  
  766. /*
  767.  * This routine, given a pointer to a LINE, and the current cursor goal
  768.  * column, return the best choice for the offset. The offset is returned.
  769.  * Used by "C-N" and "C-P".
  770.  */
  771. int
  772. getgoal(dlp)
  773. register LINE   *dlp;
  774. {
  775.         register int    c;
  776.         register int    col;
  777.         register int    newcol;
  778.         register int    dbo;
  779.  
  780.         col = 0;
  781.         dbo = 0;
  782.         while (dbo != llength(dlp)) {
  783.                 c = lgetc(dlp, dbo);
  784.         newcol = next_column(c,col);
  785.                 if (newcol > curgoal)
  786.                         break;
  787.                 col = newcol;
  788.                 ++dbo;
  789.         }
  790.         return (dbo);
  791. }
  792.  
  793. /* return the next column index, given the current char and column */
  794. int
  795. next_column(c,col)
  796. int c, col;
  797. {
  798.     if (c == '\t')
  799.                 return nextab(col);
  800.         else if (!isprint(c))
  801.                 return col+2;
  802.     else
  803.                 return col+1;
  804. }
  805.  
  806. /*
  807.  * Scroll forward by a specified number of lines, or by a full page if no
  808.  * argument.  The "2" in the arithmetic on the window size is
  809.  * the overlap; this value is the default overlap value in ITS EMACS. Because
  810.  * this zaps the top line in the display window, we have to do a hard update.
  811.  */
  812. int
  813. forwpage(f, n)
  814. int f;
  815. register int    n;
  816. {
  817.         register LINE   *lp;
  818.  
  819.         if (f == FALSE) {
  820.                 n = curwp->w_ntrows - 2;        /* Default scroll.      */
  821.                 if (n <= 0)                     /* Forget the overlap   */
  822.                         n = 1;                  /* if tiny window.      */
  823.         } else if (n < 0)
  824.                 return (backpage(f, -n));
  825. #if     CVMVAS
  826.         else                                    /* Convert from pages   */
  827.                 n *= curwp->w_ntrows;           /* to lines.            */
  828. #endif
  829.         lp = curwp->w_line.l;
  830.         while (n-- && lp!=curbp->b_line.l)
  831.                 lp = lforw(lp);
  832.         curwp->w_line.l = lp;
  833.         curwp->w_dot.l  = lp;
  834.         curwp->w_dot.o  = 0;
  835.         curwp->w_flag |= WFHARD|WFMODE;
  836.         return (TRUE);
  837. }
  838.  
  839. /*
  840.  * This command is like "forwpage", but it goes backwards. The "2", like
  841.  * above, is the overlap between the two windows. The value is from the ITS
  842.  * EMACS manual. We do a hard update for exactly the same
  843.  * reason.
  844.  */
  845. int
  846. backpage(f, n)
  847. int f;
  848. register int    n;
  849. {
  850.         register LINE   *lp;
  851.  
  852.         if (f == FALSE) {
  853.                 n = curwp->w_ntrows - 2;        /* Default scroll.      */
  854.                 if (n <= 0)                     /* Don't blow up if the */
  855.                         n = 1;                  /* window is tiny.      */
  856.         } else if (n < 0)
  857.                 return (forwpage(f, -n));
  858. #if     CVMVAS
  859.         else                                    /* Convert from pages   */
  860.                 n *= curwp->w_ntrows;           /* to lines.            */
  861. #endif
  862.         lp = curwp->w_line.l;
  863.         while (n-- && lback(lp)!=curbp->b_line.l)
  864.                 lp = lback(lp);
  865.         curwp->w_line.l = lp;
  866.         curwp->w_dot.l  = lp;
  867.         curwp->w_dot.o  = 0;
  868.         curwp->w_flag |= WFHARD;
  869.         return (TRUE);
  870. }
  871.  
  872. /*
  873.  * Scroll forward by a specified number of lines, or by a full page if no
  874.  * argument. The "2" in the arithmetic on the window size is
  875.  * the overlap; this value is the default overlap value in ITS EMACS. Because
  876.  * this zaps the top line in the display window, we have to do a hard update.
  877.  */
  878. int
  879. forwhpage(f, n)
  880. int f;
  881. register int    n;
  882. {
  883.         register LINE   *llp, *dlp;
  884.  
  885.         if (f == FALSE) {
  886.                 n = curwp->w_ntrows / 2;        /* Default scroll.      */
  887.                 if (n <= 0)                     /* Forget the overlap   */
  888.                         n = 1;                  /* if tiny window.      */
  889.         } else if (n < 0)
  890.                 return (backhpage(f, -n));
  891. #if     CVMVAS
  892.         else                                    /* Convert from pages   */
  893.                 n *= curwp->w_ntrows/2;           /* to lines.            */
  894. #endif
  895.         llp = curwp->w_line.l;
  896.         dlp = curwp->w_dot.l;
  897.         while (n-- && lforw(dlp) != curbp->b_line.l) {
  898.                 llp = lforw(llp);
  899.                 dlp = lforw(dlp);
  900.     }
  901.         curwp->w_line.l = llp;
  902.         curwp->w_dot.l  = dlp;
  903.     firstnonwhite(f,n);
  904.         curwp->w_flag |= WFHARD|WFKILLS;
  905.         return (TRUE);
  906. }
  907.  
  908. /*
  909.  * This command is like "forwpage", but it goes backwards. The "2", like
  910.  * above, is the overlap between the two windows. The value is from the ITS
  911.  * EMACS manual. We do a hard update for exactly the same
  912.  * reason.
  913.  */
  914. int
  915. backhpage(f, n)
  916. int f;
  917. register int    n;
  918. {
  919.         register LINE   *llp, *dlp;
  920.  
  921.         if (f == FALSE) {
  922.                 n = curwp->w_ntrows / 2;        /* Default scroll.      */
  923.                 if (n <= 0)                     /* Don't blow up if the */
  924.                         n = 1;                  /* window is tiny.      */
  925.         } else if (n < 0)
  926.                 return (forwhpage(f, -n));
  927. #if     CVMVAS
  928.         else                                    /* Convert from pages   */
  929.                 n *= curwp->w_ntrows/2;           /* to lines.            */
  930. #endif
  931.         llp = curwp->w_line.l;
  932.         dlp = curwp->w_dot.l;
  933.         while (n-- && lback(dlp)!=curbp->b_line.l) {
  934.                 llp = lback(llp);
  935.                 dlp = lback(dlp);
  936.     }
  937.         curwp->w_line.l = llp;
  938.         curwp->w_dot.l  = dlp;
  939.     firstnonwhite(f,n);
  940.         curwp->w_flag |= WFHARD|WFINS;
  941.         return (TRUE);
  942. }
  943.  
  944.  
  945.  
  946. /*
  947.  * Set the named mark in the current window to the value of "." in the window.
  948.  */
  949. /* ARGSUSED */
  950. int
  951. setnmmark(f,n)
  952. int f,n;
  953. {
  954.     int c,i;
  955.  
  956.     if (clexec || isnamedcmd) {
  957.         int stat;
  958.         static char cbuf[2];
  959.             if ((stat=mlreply("Set mark: ", cbuf, 2)) != TRUE)
  960.                     return stat;
  961.         c = cbuf[0];
  962.         } else {
  963.         c = kbd_key();
  964.         }
  965.     if (c < 'a' || c > 'z') {
  966.         TTbeep();
  967.         mlforce("[Invalid mark name]");
  968.         return FALSE;
  969.     }
  970.         
  971.     if (curbp->b_nmmarks == NULL) {
  972.         curbp->b_nmmarks = 
  973.             (struct MARK *)malloc(26*sizeof(struct MARK));
  974.         if (curbp->b_nmmarks == NULL) {
  975.             mlforce("[OUT OF MEMORY]");
  976.             return FALSE;
  977.         }
  978.         for (i = 0; i < 26; i++) {
  979.             curbp->b_nmmarks[i] = nullmark;
  980.         }
  981.     }
  982.         
  983.         curbp->b_nmmarks[c-'a'] = DOT;
  984.         mlwrite("[Mark %c set]",c);
  985.         return TRUE;
  986. }
  987.  
  988. int
  989. golinenmmark(f,n)
  990. int f,n;
  991. {
  992.     int status;
  993.     status = goexactnmmark(f,n);
  994.     if (status != TRUE)
  995.         return(status);
  996.     firstnonwhite(f,n);
  997.     return(TRUE);
  998. }
  999.  
  1000. /* ARGSUSED */
  1001. int
  1002. goexactnmmark(f,n)
  1003. int f,n;
  1004. {
  1005.     int c;
  1006.     int this1key;
  1007.     int useldmark;
  1008.  
  1009.     this1key = last1key;
  1010.     c = kbd_seq();
  1011.     useldmark = (last1key == this1key);  /* '' or `` */
  1012.     c = kcod2key(c);
  1013.  
  1014.     if (useldmark)
  1015.         c = '\'';
  1016.  
  1017.     return gonmmark(c);
  1018. }
  1019.  
  1020. int
  1021. gonmmark(c)
  1022. int c;
  1023. {
  1024.     register MARK *markp;
  1025.     MARK tmark;
  1026.     int found;
  1027.  
  1028.     if (!islower(c) && c != '\'') {
  1029.         TTbeep();
  1030.         mlforce("[Invalid mark name]");
  1031.         return FALSE;
  1032.     }
  1033.  
  1034.     markp = NULL;
  1035.  
  1036.     if (c == '\'') { /* use the 'last dot' mark */
  1037.         markp = &(curwp->w_lastdot);
  1038.     } else if (curbp->b_nmmarks != NULL) {
  1039.         markp = &(curbp->b_nmmarks[c-'a']);
  1040.     }
  1041.         
  1042.     found = FALSE;
  1043.     /* if we have any named marks, and the one we want isn't null */
  1044.     if (markp != NULL && !samepoint((*markp), nullmark)) {
  1045.         register LINE *lp;
  1046.         for (lp = lforw(curbp->b_line.l);
  1047.                 lp != curbp->b_line.l; lp = lforw(lp)) {
  1048.             if ((*markp).l == lp) {
  1049.                 found = TRUE;
  1050.                 break;
  1051.             }
  1052.         }
  1053.     }
  1054.     if (!found) {
  1055.         TTbeep();
  1056.         mlforce("[Mark not set]");
  1057.         return (FALSE);
  1058.     }
  1059.     
  1060.     /* save current dot */
  1061.     tmark = DOT;
  1062.  
  1063.     /* move to the selected mark */
  1064.     DOT = *markp;
  1065.  
  1066.     if (!doingopcmd)    /* reset last-dot-mark to old dot */
  1067.         curwp->w_lastdot = tmark;
  1068.  
  1069.         curwp->w_flag |= WFMOVE;
  1070.         return (TRUE);
  1071. }
  1072.  
  1073. /*
  1074.  * Set the mark in the current window to the value of "." in the window. No
  1075.  * errors are possible.
  1076.  */
  1077. int
  1078. setmark()
  1079. {
  1080.     MK = DOT;
  1081.         return (TRUE);
  1082. }
  1083.  
  1084. /* ARGSUSED */
  1085. int
  1086. gomark(f,n)
  1087. int f,n;
  1088. {
  1089.     DOT = MK;
  1090.         curwp->w_flag |= WFMOVE;
  1091.         return (TRUE);
  1092. }
  1093.  
  1094. /* this odd routine puts us at the internal mark, plus an offset of lines */
  1095. /*  n == 1 leaves us at mark, n == 2 one line down, etc. */
  1096. /*  this is for the use of stuttered commands, and line oriented regions */
  1097. int
  1098. godotplus(f,n)
  1099. int f,n;
  1100. {
  1101.     int s;
  1102.     if (!f || n == 1)
  1103.             return (TRUE);
  1104.     if (n < 1)
  1105.             return (FALSE);
  1106.     s = forwline(TRUE,n-1);
  1107.     if (s && is_header_line(DOT, curbp))
  1108.         s = backline(FALSE,1);
  1109.     return s;
  1110. }
  1111.  
  1112. /*
  1113.  * Swap the values of "." and "mark" in the current window. This is pretty
  1114.  * easy, because all of the hard work gets done by the standard routine
  1115.  * that moves the mark about. The only possible error is "no mark".
  1116.  */
  1117. void
  1118. swapmark()
  1119. {
  1120.     MARK odot;
  1121.  
  1122.         if (samepoint(MK, nullmark)) {
  1123.                 mlforce("BUG: No mark ");
  1124.                 return;
  1125.         }
  1126.     odot = DOT;
  1127.     DOT = MK;
  1128.     MK = odot;
  1129.         curwp->w_flag |= WFMOVE;
  1130.         return;
  1131. }
  1132.  
  1133.  
  1134.  
  1135. #if    NeWS
  1136. /* SETCURSOR
  1137.  *
  1138.  * Mouse support function.  Put the cursor to the requested location.
  1139.  * The cursor will be put just after the last character of the line if 
  1140.  * requested past the line.  The coordinates are expected in the command
  1141.  * stream.
  1142.  *   In the case of multiple windows, the window indicated by the mouse
  1143.  * is located and made the current window.
  1144.  */
  1145. setcursor()
  1146. {
  1147. int    row, col, pasteol ;
  1148. register LINE    *dlp;
  1149. WINDOW *wp0 ;        /* current window on entry */
  1150.  
  1151.     row = tgetc() ;
  1152.     col = tgetc() ;
  1153.  
  1154. /* find the window we are pointing to */
  1155.     wp0 = curwp ;
  1156.     while ( row < curwp->w_toprow ||
  1157.         row > curwp->w_ntrows + curwp->w_toprow ) {
  1158.         nextwind(FALSE,0) ;
  1159.         if ( curwp == wp0 ) break ;    /* full circle */
  1160.     }
  1161.  
  1162. /* move to the right row */
  1163.     row -= curwp->w_toprow ;
  1164.     dlp = curwp->w_line.l ;            /* get pointer to 1st line */
  1165.     while ( row-- && (dlp != curbp->b_line.l) ) dlp = lforw(dlp) ;
  1166.     curwp->w_dot.l = dlp ;            /* set dot line pointer */
  1167.  
  1168.     /* now move the dot over until near the requested column */
  1169.         curgoal = col + w_val(curwp, WVAL_SIDEWAYS);
  1170.     curwp->w_dot.o = getgoal(dlp) ;
  1171.     curwp->w_flag |= WFMOVE;
  1172.     return;
  1173. }
  1174. #endif
  1175.  
  1176. #if X11
  1177. void
  1178. setcursor(row, col)
  1179. int row, col;
  1180. {
  1181.     register LINE *dlp;
  1182.     WINDOW     *wp0;        /* current window on entry */
  1183.  
  1184. /* find the window we are pointing to */
  1185.     wp0 = curwp;
  1186.     while (row < curwp->w_toprow ||
  1187.         row > curwp->w_ntrows + curwp->w_toprow) {
  1188.     nextwind(FALSE, 0);
  1189.     if (curwp == wp0)
  1190.         break;        /* full circle */
  1191.     }
  1192.  
  1193. /* move to the right row */
  1194.     row -= curwp->w_toprow;
  1195.     dlp = curwp->w_line.l;    /* get pointer to 1st line */
  1196.     while (row-- && (dlp != curbp->b_line.l))
  1197.     dlp = lforw(dlp);
  1198.     DOT.l = dlp;    /* set dot line pointer */
  1199.  
  1200.     /* now move the dot over until near the requested column */
  1201.     curgoal = col + w_val(curwp, WVAL_SIDEWAYS);
  1202.     DOT.o = getgoal(dlp);
  1203.     /* don't allow the cursor to be set past end of line unless in
  1204.      * insert mode
  1205.      */
  1206.     if (DOT.o >= llength(dlp) && DOT.o > 0 && !insertmode)
  1207.         DOT.o--;
  1208.     curwp->w_flag |= WFMOVE;
  1209.     return;
  1210. }
  1211. #endif
  1212.