--- /dev/null
+/* $OpenBSD: basic.c,v 1.37 2012/06/18 09:26:03 lum Exp $ */
+
+/* This file is in the public domain */
+
+/*
+ * Basic cursor motion commands.
+ *
+ * The routines in this file are the basic
+ * command functions for moving the cursor around on
+ * the screen, setting mark, and swapping dot with
+ * mark. Only moves between lines, which might make the
+ * current buffer framing bad, are hard.
+ */
+#include "def.h"
+
+#include <ctype.h>
+
+/*
+ * Go to beginning of line.
+ */
+/* ARGSUSED */
+int
+gotobol(int f, int n)
+{
+ curwp->w_doto = 0;
+ return (TRUE);
+}
+
+/*
+ * Move cursor backwards. Do the
+ * right thing if the count is less than
+ * 0. Error if you try to move back from
+ * the beginning of the buffer.
+ */
+/* ARGSUSED */
+int
+backchar(int f, int n)
+{
+ struct line *lp;
+
+ if (n < 0)
+ return (forwchar(f, -n));
+ while (n--) {
+ if (curwp->w_doto == 0) {
+ if ((lp = lback(curwp->w_dotp)) == curbp->b_headp) {
+ if (!(f & FFRAND))
+ ewprintf("Beginning of buffer");
+ return (FALSE);
+ }
+ curwp->w_dotp = lp;
+ curwp->w_doto = llength(lp);
+ curwp->w_rflag |= WFMOVE;
+ curwp->w_dotline--;
+ } else
+ curwp->w_doto--;
+ }
+ return (TRUE);
+}
+
+/*
+ * Go to end of line.
+ */
+/* ARGSUSED */
+int
+gotoeol(int f, int n)
+{
+ curwp->w_doto = llength(curwp->w_dotp);
+ return (TRUE);
+}
+
+/*
+ * Move cursor forwards. Do the
+ * right thing if the count is less than
+ * 0. Error if you try to move forward
+ * from the end of the buffer.
+ */
+/* ARGSUSED */
+int
+forwchar(int f, int n)
+{
+ if (n < 0)
+ return (backchar(f, -n));
+ while (n--) {
+ if (curwp->w_doto == llength(curwp->w_dotp)) {
+ curwp->w_dotp = lforw(curwp->w_dotp);
+ if (curwp->w_dotp == curbp->b_headp) {
+ curwp->w_dotp = lback(curwp->w_dotp);
+ if (!(f & FFRAND))
+ ewprintf("End of buffer");
+ return (FALSE);
+ }
+ curwp->w_doto = 0;
+ curwp->w_dotline++;
+ curwp->w_rflag |= WFMOVE;
+ } else
+ curwp->w_doto++;
+ }
+ return (TRUE);
+}
+
+/*
+ * Go to the beginning of the
+ * buffer. Setting WFFULL is conservative,
+ * but almost always the case.
+ */
+int
+gotobob(int f, int n)
+{
+ (void) setmark(f, n);
+ curwp->w_dotp = bfirstlp(curbp);
+ curwp->w_doto = 0;
+ curwp->w_rflag |= WFFULL;
+ curwp->w_dotline = 1;
+ return (TRUE);
+}
+
+/*
+ * Go to the end of the buffer. Leave dot 3 lines from the bottom of the
+ * window if buffer length is longer than window length; same as emacs.
+ * Setting WFFULL is conservative, but almost always the case.
+ */
+int
+gotoeob(int f, int n)
+{
+ struct line *lp;
+
+ (void) setmark(f, n);
+ curwp->w_dotp = blastlp(curbp);
+ curwp->w_doto = llength(curwp->w_dotp);
+ curwp->w_dotline = curwp->w_bufp->b_lines;
+
+ lp = curwp->w_dotp;
+ n = curwp->w_ntrows - 3;
+
+ if (n < curwp->w_bufp->b_lines && n >= 3) {
+ while (n--)
+ curwp->w_dotp = lback(curwp->w_dotp);
+
+ curwp->w_linep = curwp->w_dotp;
+ curwp->w_dotp = lp;
+ }
+ curwp->w_rflag |= WFFULL;
+ return (TRUE);
+}
+
+/*
+ * Move forward by full lines.
+ * If the number of lines to move is less
+ * than zero, call the backward line function to
+ * actually do it. The last command controls how
+ * the goal column is set.
+ */
+/* ARGSUSED */
+int
+forwline(int f, int n)
+{
+ struct line *dlp;
+
+ if (n < 0)
+ return (backline(f | FFRAND, -n));
+ if ((dlp = curwp->w_dotp) == curbp->b_headp)
+ return(TRUE);
+ if ((lastflag & CFCPCN) == 0) /* Fix goal. */
+ setgoal();
+ thisflag |= CFCPCN;
+ if (n == 0)
+ return (TRUE);
+ while (n--) {
+ dlp = lforw(dlp);
+ if (dlp == curbp->b_headp) {
+ curwp->w_dotp = lback(dlp);
+ curwp->w_doto = llength(curwp->w_dotp);
+ curwp->w_rflag |= WFMOVE;
+ return (TRUE);
+ }
+ curwp->w_dotline++;
+ }
+ curwp->w_rflag |= WFMOVE;
+ curwp->w_dotp = dlp;
+ curwp->w_doto = getgoal(dlp);
+
+ return (TRUE);
+}
+
+/*
+ * This function is like "forwline", but
+ * goes backwards. The scheme is exactly the same.
+ * Check for arguments that are less than zero and
+ * call your alternate. Figure out the new line and
+ * call "movedot" to perform the motion.
+ */
+/* ARGSUSED */
+int
+backline(int f, int n)
+{
+ struct line *dlp;
+
+ if (n < 0)
+ return (forwline(f | FFRAND, -n));
+ if ((lastflag & CFCPCN) == 0) /* Fix goal. */
+ setgoal();
+ thisflag |= CFCPCN;
+ dlp = curwp->w_dotp;
+ while (n-- && lback(dlp) != curbp->b_headp) {
+ dlp = lback(dlp);
+ curwp->w_dotline--;
+ }
+ curwp->w_dotp = dlp;
+ curwp->w_doto = getgoal(dlp);
+ curwp->w_rflag |= WFMOVE;
+ return (TRUE);
+}
+
+/*
+ * Set the current goal column, which is saved in the external variable
+ * "curgoal", to the current cursor column. The column is never off
+ * the edge of the screen; it's more like display then show position.
+ */
+void
+setgoal(void)
+{
+ curgoal = getcolpos(); /* Get the position. */
+ /* we can now display past end of display, don't chop! */
+}
+
+/*
+ * This routine looks at a line (pointed
+ * to by the LINE pointer "dlp") and the current
+ * vertical motion goal column (set by the "setgoal"
+ * routine above) and returns the best offset to use
+ * when a vertical motion is made into the line.
+ */
+int
+getgoal(struct line *dlp)
+{
+ int c, i, col = 0;
+ char tmp[5];
+
+
+ for (i = 0; i < llength(dlp); i++) {
+ c = lgetc(dlp, i);
+ if (c == '\t'
+#ifdef NOTAB
+ && !(curbp->b_flag & BFNOTAB)
+#endif
+ ) {
+ col |= 0x07;
+ col++;
+ } else if (ISCTRL(c) != FALSE) {
+ col += 2;
+ } else if (isprint(c))
+ col++;
+ else {
+ col += snprintf(tmp, sizeof(tmp), "\\%o", c);
+ }
+ if (col > curgoal)
+ break;
+ }
+ return (i);
+}
+
+/*
+ * Scroll forward by a specified number
+ * of lines, or by a full page if no argument.
+ * The "2" is the window overlap (this is the default
+ * value from ITS EMACS). Because the top line in
+ * the window is zapped, we have to do a hard
+ * update and get it back.
+ */
+/* ARGSUSED */
+int
+forwpage(int f, int n)
+{
+ struct line *lp;
+
+ if (!(f & FFARG)) {
+ n = curwp->w_ntrows - 2; /* Default scroll. */
+ if (n <= 0) /* Forget the overlap */
+ n = 1; /* if tiny window. */
+ } else if (n < 0)
+ return (backpage(f | FFRAND, -n));
+
+ lp = curwp->w_linep;
+ while (n--)
+ if ((lp = lforw(lp)) == curbp->b_headp) {
+ ttbeep();
+ ewprintf("End of buffer");
+ return(TRUE);
+ }
+
+ curwp->w_linep = lp;
+ curwp->w_rflag |= WFFULL;
+
+ /* if in current window, don't move dot */
+ for (n = curwp->w_ntrows; n-- && lp != curbp->b_headp; lp = lforw(lp))
+ if (lp == curwp->w_dotp)
+ return (TRUE);
+
+ /* Advance the dot the slow way, for line nos */
+ while (curwp->w_dotp != curwp->w_linep) {
+ curwp->w_dotp = lforw(curwp->w_dotp);
+ curwp->w_dotline++;
+ }
+ curwp->w_doto = 0;
+ return (TRUE);
+}
+
+/*
+ * This command is like "forwpage",
+ * but it goes backwards. The "2", like above,
+ * is the overlap between the two windows. The
+ * value is from the ITS EMACS manual. The
+ * hard update is done because the top line in
+ * the window is zapped.
+ */
+/* ARGSUSED */
+int
+backpage(int f, int n)
+{
+ struct line *lp, *lp2;
+
+ if (!(f & FFARG)) {
+ n = curwp->w_ntrows - 2; /* Default scroll. */
+ if (n <= 0) /* Don't blow up if the */
+ return (backline(f, 1));/* window is tiny. */
+ } else if (n < 0)
+ return (forwpage(f | FFRAND, -n));
+
+ lp = lp2 = curwp->w_linep;
+
+ while (n-- && lback(lp) != curbp->b_headp) {
+ lp = lback(lp);
+ }
+ if (lp == curwp->w_linep) {
+ ttbeep();
+ ewprintf("Beginning of buffer");
+ }
+ curwp->w_linep = lp;
+ curwp->w_rflag |= WFFULL;
+
+ /* if in current window, don't move dot */
+ for (n = curwp->w_ntrows; n-- && lp != curbp->b_headp; lp = lforw(lp))
+ if (lp == curwp->w_dotp)
+ return (TRUE);
+
+ lp2 = lforw(lp2);
+
+ /* Move the dot the slow way, for line nos */
+ while (curwp->w_dotp != lp2) {
+ if (curwp->w_dotline <= curwp->w_ntrows)
+ return (TRUE);
+ curwp->w_dotp = lback(curwp->w_dotp);
+ curwp->w_dotline--;
+ }
+ curwp->w_doto = 0;
+ return (TRUE);
+}
+
+/*
+ * These functions are provided for compatibility with Gosling's Emacs. They
+ * are used to scroll the display up (or down) one line at a time.
+ */
+int
+forw1page(int f, int n)
+{
+ if (!(f & FFARG)) {
+ n = 1;
+ f = FFUNIV;
+ }
+ forwpage(f | FFRAND, n);
+ return (TRUE);
+}
+
+int
+back1page(int f, int n)
+{
+ if (!(f & FFARG)) {
+ n = 1;
+ f = FFUNIV;
+ }
+ backpage(f | FFRAND, n);
+ return (TRUE);
+}
+
+/*
+ * Page the other window. Check to make sure it exists, then
+ * nextwind, forwpage and restore window pointers.
+ */
+int
+pagenext(int f, int n)
+{
+ struct mgwin *wp;
+
+ if (wheadp->w_wndp == NULL) {
+ ewprintf("No other window");
+ return (FALSE);
+ }
+ wp = curwp;
+ (void) nextwind(f, n);
+ (void) forwpage(f, n);
+ curwp = wp;
+ curbp = wp->w_bufp;
+ return (TRUE);
+}
+
+/*
+ * Internal set mark routine, used by other functions (daveb).
+ */
+void
+isetmark(void)
+{
+ curwp->w_markp = curwp->w_dotp;
+ curwp->w_marko = curwp->w_doto;
+ curwp->w_markline = curwp->w_dotline;
+}
+
+/*
+ * Set the mark in the current window
+ * to the value of dot. A message is written to
+ * the echo line. (ewprintf knows about macros)
+ */
+/* ARGSUSED */
+int
+setmark(int f, int n)
+{
+ isetmark();
+ ewprintf("Mark set");
+ return (TRUE);
+}
+
+/* Clear the mark, if set. */
+/* ARGSUSED */
+int
+clearmark(int f, int n)
+{
+ if (!curwp->w_markp)
+ return (FALSE);
+
+ curwp->w_markp = NULL;
+ curwp->w_marko = 0;
+ curwp->w_markline = 0;
+
+ return (TRUE);
+}
+
+/*
+ * Swap the values of "dot" and "mark" in
+ * the current window. This is pretty easy, because
+ * all of the hard work gets done by the standard routine
+ * that moves the mark about. The only possible
+ * error is "no mark".
+ */
+/* ARGSUSED */
+int
+swapmark(int f, int n)
+{
+ struct line *odotp;
+ int odoto, odotline;
+
+ if (curwp->w_markp == NULL) {
+ ewprintf("No mark in this window");
+ return (FALSE);
+ }
+ odotp = curwp->w_dotp;
+ odoto = curwp->w_doto;
+ odotline = curwp->w_dotline;
+ curwp->w_dotp = curwp->w_markp;
+ curwp->w_doto = curwp->w_marko;
+ curwp->w_dotline = curwp->w_markline;
+ curwp->w_markp = odotp;
+ curwp->w_marko = odoto;
+ curwp->w_markline = odotline;
+ curwp->w_rflag |= WFMOVE;
+ return (TRUE);
+}
+
+/*
+ * Go to a specific line, mostly for
+ * looking up errors in C programs, which give the
+ * error a line number. If an argument is present, then
+ * it is the line number, else prompt for a line number
+ * to use.
+ */
+/* ARGSUSED */
+int
+gotoline(int f, int n)
+{
+ struct line *clp;
+ char buf[32], *bufp;
+ const char *err;
+
+ if (!(f & FFARG)) {
+ if ((bufp = eread("Goto line: ", buf, sizeof(buf),
+ EFNUL | EFNEW | EFCR)) == NULL)
+ return (ABORT);
+ if (bufp[0] == '\0')
+ return (ABORT);
+ n = (int)strtonum(buf, INT_MIN, INT_MAX, &err);
+ if (err) {
+ ewprintf("Line number %s", err);
+ return (FALSE);
+ }
+ }
+ if (n >= 0) {
+ if (n == 0)
+ n++;
+ curwp->w_dotline = n;
+ clp = lforw(curbp->b_headp); /* "clp" is first line */
+ while (--n > 0) {
+ if (lforw(clp) == curbp->b_headp) {
+ curwp->w_dotline = curwp->w_bufp->b_lines;
+ break;
+ }
+ clp = lforw(clp);
+ }
+ } else {
+ curwp->w_dotline = curwp->w_bufp->b_lines + n;
+ clp = lback(curbp->b_headp); /* "clp" is last line */
+ while (n < 0) {
+ if (lback(clp) == curbp->b_headp) {
+ curwp->w_dotline = 1;
+ break;
+ }
+ clp = lback(clp);
+ n++;
+ }
+ }
+ curwp->w_dotp = clp;
+ curwp->w_doto = 0;
+ curwp->w_rflag |= WFMOVE;
+ return (TRUE);
+}