Annotation of src/usr.bin/mg/basic.c, Revision 1.23
1.23 ! kjell 1: /* $OpenBSD: basic.c,v 1.22 2006/05/28 23:30:16 kjell Exp $ */
1.19 kjell 2:
3: /* This file is in the public domain */
1.4 niklas 4:
1.1 deraadt 5: /*
6: * Basic cursor motion commands.
7: *
8: * The routines in this file are the basic
9: * command functions for moving the cursor around on
10: * the screen, setting mark, and swapping dot with
11: * mark. Only moves between lines, which might make the
12: * current buffer framing bad, are hard.
13: */
1.3 millert 14: #include "def.h"
1.1 deraadt 15:
1.14 vincent 16: #include <ctype.h>
1.1 deraadt 17:
18: /*
19: * Go to beginning of line.
20: */
1.3 millert 21: /* ARGSUSED */
22: int
1.12 vincent 23: gotobol(int f, int n)
1.1 deraadt 24: {
1.3 millert 25: curwp->w_doto = 0;
1.1 deraadt 26: return (TRUE);
27: }
28:
29: /*
30: * Move cursor backwards. Do the
31: * right thing if the count is less than
32: * 0. Error if you try to move back from
33: * the beginning of the buffer.
34: */
1.3 millert 35: /* ARGSUSED */
36: int
1.12 vincent 37: backchar(int f, int n)
1.1 deraadt 38: {
1.21 deraadt 39: struct line *lp;
1.1 deraadt 40:
1.3 millert 41: if (n < 0)
1.18 db 42: return (forwchar(f, -n));
1.1 deraadt 43: while (n--) {
44: if (curwp->w_doto == 0) {
1.3 millert 45: if ((lp = lback(curwp->w_dotp)) == curbp->b_linep) {
1.1 deraadt 46: if (!(f & FFRAND))
47: ewprintf("Beginning of buffer");
48: return (FALSE);
49: }
1.3 millert 50: curwp->w_dotp = lp;
51: curwp->w_doto = llength(lp);
1.1 deraadt 52: curwp->w_flag |= WFMOVE;
1.23 ! kjell 53: curwp->w_dotline--;
1.1 deraadt 54: } else
55: curwp->w_doto--;
56: }
1.18 db 57: return (TRUE);
1.1 deraadt 58: }
59:
60: /*
61: * Go to end of line.
62: */
1.3 millert 63: /* ARGSUSED */
64: int
1.12 vincent 65: gotoeol(int f, int n)
1.1 deraadt 66: {
1.3 millert 67: curwp->w_doto = llength(curwp->w_dotp);
1.1 deraadt 68: return (TRUE);
69: }
70:
71: /*
72: * Move cursor forwards. Do the
73: * right thing if the count is less than
74: * 0. Error if you try to move forward
75: * from the end of the buffer.
76: */
1.3 millert 77: /* ARGSUSED */
78: int
1.12 vincent 79: forwchar(int f, int n)
1.1 deraadt 80: {
1.3 millert 81: if (n < 0)
1.18 db 82: return (backchar(f, -n));
1.1 deraadt 83: while (n--) {
84: if (curwp->w_doto == llength(curwp->w_dotp)) {
1.3 millert 85: curwp->w_dotp = lforw(curwp->w_dotp);
1.1 deraadt 86: if (curwp->w_dotp == curbp->b_linep) {
87: curwp->w_dotp = lback(curwp->w_dotp);
88: if (!(f & FFRAND))
89: ewprintf("End of buffer");
1.18 db 90: return (FALSE);
1.1 deraadt 91: }
1.3 millert 92: curwp->w_doto = 0;
1.23 ! kjell 93: curwp->w_dotline++;
1.1 deraadt 94: curwp->w_flag |= WFMOVE;
95: } else
96: curwp->w_doto++;
97: }
1.18 db 98: return (TRUE);
1.1 deraadt 99: }
100:
101: /*
102: * Go to the beginning of the
1.22 kjell 103: * buffer. Setting WFFULL is conservative,
1.1 deraadt 104: * but almost always the case.
105: */
1.3 millert 106: int
1.12 vincent 107: gotobob(int f, int n)
1.1 deraadt 108: {
1.6 art 109: (void) setmark(f, n);
1.3 millert 110: curwp->w_dotp = lforw(curbp->b_linep);
111: curwp->w_doto = 0;
1.22 kjell 112: curwp->w_flag |= WFFULL;
1.23 ! kjell 113: curwp->w_dotline = 1;
1.18 db 114: return (TRUE);
1.1 deraadt 115: }
116:
117: /*
118: * Go to the end of the buffer.
1.22 kjell 119: * Setting WFFULL is conservative, but
1.1 deraadt 120: * almost always the case.
121: */
1.3 millert 122: int
1.12 vincent 123: gotoeob(int f, int n)
1.1 deraadt 124: {
1.6 art 125: (void) setmark(f, n);
1.3 millert 126: curwp->w_dotp = lback(curbp->b_linep);
127: curwp->w_doto = llength(curwp->w_dotp);
1.23 ! kjell 128: curwp->w_dotline = curwp->w_bufp->b_lines;
1.22 kjell 129: curwp->w_flag |= WFFULL;
1.18 db 130: return (TRUE);
1.1 deraadt 131: }
132:
133: /*
134: * Move forward by full lines.
135: * If the number of lines to move is less
136: * than zero, call the backward line function to
137: * actually do it. The last command controls how
138: * the goal column is set.
139: */
1.3 millert 140: /* ARGSUSED */
141: int
1.12 vincent 142: forwline(int f, int n)
1.1 deraadt 143: {
1.21 deraadt 144: struct line *dlp;
1.1 deraadt 145:
146: if (n < 0)
1.18 db 147: return (backline(f | FFRAND, -n));
1.23 ! kjell 148: if ((dlp = curwp->w_dotp) == curbp->b_linep)
! 149: return(TRUE);
1.14 vincent 150: if ((lastflag & CFCPCN) == 0) /* Fix goal. */
1.1 deraadt 151: setgoal();
152: thisflag |= CFCPCN;
1.3 millert 153: if (n == 0)
1.18 db 154: return (TRUE);
1.23 ! kjell 155: while (n--) {
1.1 deraadt 156: dlp = lforw(dlp);
1.23 ! kjell 157: if (dlp == curbp->b_linep) {
! 158: curwp->w_dotp = lback(dlp);
! 159: curwp->w_doto = llength(curwp->w_dotp);
! 160: curwp->w_flag |= WFMOVE;
! 161: return (TRUE);
1.1 deraadt 162: }
1.23 ! kjell 163: curwp->w_dotline++;
1.1 deraadt 164: }
1.23 ! kjell 165: curwp->w_flag |= WFMOVE;
! 166: curwp->w_dotp = dlp;
! 167: curwp->w_doto = getgoal(dlp);
! 168:
1.18 db 169: return (TRUE);
1.1 deraadt 170: }
171:
172: /*
173: * This function is like "forwline", but
174: * goes backwards. The scheme is exactly the same.
175: * Check for arguments that are less than zero and
176: * call your alternate. Figure out the new line and
177: * call "movedot" to perform the motion.
178: */
1.3 millert 179: /* ARGSUSED */
180: int
1.12 vincent 181: backline(int f, int n)
1.1 deraadt 182: {
1.21 deraadt 183: struct line *dlp;
1.1 deraadt 184:
1.3 millert 185: if (n < 0)
1.18 db 186: return (forwline(f | FFRAND, -n));
1.14 vincent 187: if ((lastflag & CFCPCN) == 0) /* Fix goal. */
1.1 deraadt 188: setgoal();
189: thisflag |= CFCPCN;
190: dlp = curwp->w_dotp;
1.23 ! kjell 191: while (n-- && lback(dlp) != curbp->b_linep) {
1.1 deraadt 192: dlp = lback(dlp);
1.23 ! kjell 193: curwp->w_dotline--;
! 194: }
1.3 millert 195: curwp->w_dotp = dlp;
196: curwp->w_doto = getgoal(dlp);
1.1 deraadt 197: curwp->w_flag |= WFMOVE;
1.18 db 198: return (TRUE);
1.1 deraadt 199: }
200:
201: /*
1.3 millert 202: * Set the current goal column, which is saved in the external variable
203: * "curgoal", to the current cursor column. The column is never off
204: * the edge of the screen; it's more like display then show position.
1.1 deraadt 205: */
1.6 art 206: void
1.12 vincent 207: setgoal(void)
1.3 millert 208: {
1.17 deraadt 209: curgoal = getcolpos(); /* Get the position. */
1.3 millert 210: /* we can now display past end of display, don't chop! */
1.1 deraadt 211: }
212:
213: /*
214: * This routine looks at a line (pointed
215: * to by the LINE pointer "dlp") and the current
216: * vertical motion goal column (set by the "setgoal"
217: * routine above) and returns the best offset to use
218: * when a vertical motion is made into the line.
219: */
1.3 millert 220: int
1.21 deraadt 221: getgoal(struct line *dlp)
1.3 millert 222: {
1.14 vincent 223: int c, i, col = 0;
224:
225: for (i = 0; i < llength(dlp); i++) {
226: c = lgetc(dlp, i);
1.1 deraadt 227: if (c == '\t'
228: #ifdef NOTAB
1.3 millert 229: && !(curbp->b_flag & BFNOTAB)
1.1 deraadt 230: #endif
1.14 vincent 231: ) {
232: col |= 0x07;
233: col++;
234: } else if (ISCTRL(c) != FALSE) {
235: col += 2;
236: } else if (isprint(c))
237: col++;
238: else {
239: char tmp[5];
1.15 deraadt 240:
1.18 db 241: snprintf(tmp, sizeof(tmp), "\\%o", c);
1.15 deraadt 242: col += strlen(tmp);
1.14 vincent 243: }
244: if (col > curgoal)
1.1 deraadt 245: break;
246: }
1.14 vincent 247: return (i);
1.1 deraadt 248: }
249:
250: /*
251: * Scroll forward by a specified number
252: * of lines, or by a full page if no argument.
253: * The "2" is the window overlap (this is the default
254: * value from ITS EMACS). Because the top line in
255: * the window is zapped, we have to do a hard
256: * update and get it back.
257: */
1.3 millert 258: /* ARGSUSED */
259: int
1.12 vincent 260: forwpage(int f, int n)
1.1 deraadt 261: {
1.21 deraadt 262: struct line *lp;
1.1 deraadt 263:
264: if (!(f & FFARG)) {
1.3 millert 265: n = curwp->w_ntrows - 2; /* Default scroll. */
266: if (n <= 0) /* Forget the overlap */
267: n = 1; /* if tiny window. */
1.1 deraadt 268: } else if (n < 0)
1.18 db 269: return (backpage(f | FFRAND, -n));
1.1 deraadt 270: #ifdef CVMVAS
1.3 millert 271: else /* Convert from pages */
272: n *= curwp->w_ntrows; /* to lines. */
1.1 deraadt 273: #endif
274: lp = curwp->w_linep;
1.23 ! kjell 275: while (n-- && lforw(lp) != curbp->b_linep) {
1.1 deraadt 276: lp = lforw(lp);
1.23 ! kjell 277: curwp->w_dotline++;
! 278: }
1.1 deraadt 279: curwp->w_linep = lp;
1.22 kjell 280: curwp->w_flag |= WFFULL;
1.1 deraadt 281: /* if in current window, don't move dot */
1.3 millert 282: for (n = curwp->w_ntrows; n-- && lp != curbp->b_linep; lp = lforw(lp))
283: if (lp == curwp->w_dotp)
1.18 db 284: return (TRUE);
1.3 millert 285: curwp->w_dotp = curwp->w_linep;
286: curwp->w_doto = 0;
1.18 db 287: return (TRUE);
1.1 deraadt 288: }
289:
290: /*
291: * This command is like "forwpage",
292: * but it goes backwards. The "2", like above,
293: * is the overlap between the two windows. The
294: * value is from the ITS EMACS manual. The
295: * hard update is done because the top line in
296: * the window is zapped.
297: */
1.3 millert 298: /* ARGSUSED */
299: int
1.12 vincent 300: backpage(int f, int n)
1.1 deraadt 301: {
1.21 deraadt 302: struct line *lp;
1.1 deraadt 303:
304: if (!(f & FFARG)) {
1.3 millert 305: n = curwp->w_ntrows - 2; /* Default scroll. */
306: if (n <= 0) /* Don't blow up if the */
307: n = 1; /* window is tiny. */
1.1 deraadt 308: } else if (n < 0)
1.18 db 309: return (forwpage(f | FFRAND, -n));
1.1 deraadt 310: #ifdef CVMVAS
1.3 millert 311: else /* Convert from pages */
312: n *= curwp->w_ntrows; /* to lines. */
1.1 deraadt 313: #endif
314: lp = curwp->w_linep;
1.23 ! kjell 315: while (n-- && lback(lp) != curbp->b_linep) {
1.1 deraadt 316: lp = lback(lp);
1.23 ! kjell 317: curwp->w_dotline--;
! 318: }
1.1 deraadt 319: curwp->w_linep = lp;
1.22 kjell 320: curwp->w_flag |= WFFULL;
1.1 deraadt 321: /* if in current window, don't move dot */
1.3 millert 322: for (n = curwp->w_ntrows; n-- && lp != curbp->b_linep; lp = lforw(lp))
323: if (lp == curwp->w_dotp)
1.18 db 324: return (TRUE);
1.1 deraadt 325: curwp->w_dotp = curwp->w_linep;
326: curwp->w_doto = 0;
1.18 db 327: return (TRUE);
1.1 deraadt 328: }
329:
1.3 millert 330: /*
331: * These functions are provided for compatibility with Gosling's Emacs. They
332: * are used to scroll the display up (or down) one line at a time.
1.1 deraadt 333: */
1.7 deraadt 334: int
1.12 vincent 335: forw1page(int f, int n)
1.1 deraadt 336: {
1.3 millert 337: if (!(f & FFARG)) {
338: n = 1;
1.1 deraadt 339: f = FFUNIV;
340: }
1.3 millert 341: forwpage(f | FFRAND, n);
1.18 db 342: return (TRUE);
1.1 deraadt 343: }
344:
1.7 deraadt 345: int
1.12 vincent 346: back1page(int f, int n)
1.1 deraadt 347: {
348: if (!(f & FFARG)) {
1.3 millert 349: n = 1;
1.1 deraadt 350: f = FFUNIV;
351: }
1.3 millert 352: backpage(f | FFRAND, n);
1.18 db 353: return (TRUE);
1.1 deraadt 354: }
355:
356: /*
357: * Page the other window. Check to make sure it exists, then
358: * nextwind, forwpage and restore window pointers.
359: */
1.3 millert 360: int
1.12 vincent 361: pagenext(int f, int n)
1.1 deraadt 362: {
1.21 deraadt 363: struct mgwin *wp;
1.1 deraadt 364:
365: if (wheadp->w_wndp == NULL) {
366: ewprintf("No other window");
1.18 db 367: return (FALSE);
1.1 deraadt 368: }
369: wp = curwp;
1.6 art 370: (void) nextwind(f, n);
371: (void) forwpage(f, n);
1.1 deraadt 372: curwp = wp;
373: curbp = wp->w_bufp;
1.18 db 374: return (TRUE);
1.1 deraadt 375: }
376:
377: /*
378: * Internal set mark routine, used by other functions (daveb).
379: */
1.6 art 380: void
1.12 vincent 381: isetmark(void)
1.1 deraadt 382: {
383: curwp->w_markp = curwp->w_dotp;
384: curwp->w_marko = curwp->w_doto;
1.23 ! kjell 385: curwp->w_markline = curwp->w_dotline;
1.1 deraadt 386: }
387:
388: /*
389: * Set the mark in the current window
390: * to the value of dot. A message is written to
391: * the echo line. (ewprintf knows about macros)
392: */
1.3 millert 393: /* ARGSUSED */
394: int
1.12 vincent 395: setmark(int f, int n)
1.1 deraadt 396: {
397: isetmark();
398: ewprintf("Mark set");
1.18 db 399: return (TRUE);
1.1 deraadt 400: }
401:
402: /*
403: * Swap the values of "dot" and "mark" in
404: * the current window. This is pretty easy, because
405: * all of the hard work gets done by the standard routine
406: * that moves the mark about. The only possible
407: * error is "no mark".
408: */
1.3 millert 409: /* ARGSUSED */
410: int
1.12 vincent 411: swapmark(int f, int n)
1.1 deraadt 412: {
1.21 deraadt 413: struct line *odotp;
1.23 ! kjell 414: int odoto, odotline;
1.1 deraadt 415:
416: if (curwp->w_markp == NULL) {
417: ewprintf("No mark in this window");
1.18 db 418: return (FALSE);
1.1 deraadt 419: }
420: odotp = curwp->w_dotp;
421: odoto = curwp->w_doto;
1.23 ! kjell 422: odotline = curwp->w_dotline;
1.3 millert 423: curwp->w_dotp = curwp->w_markp;
424: curwp->w_doto = curwp->w_marko;
1.23 ! kjell 425: curwp->w_dotline = curwp->w_markline;
1.1 deraadt 426: curwp->w_markp = odotp;
427: curwp->w_marko = odoto;
1.23 ! kjell 428: curwp->w_markline = odotline;
1.1 deraadt 429: curwp->w_flag |= WFMOVE;
1.18 db 430: return (TRUE);
1.1 deraadt 431: }
432:
433: /*
434: * Go to a specific line, mostly for
435: * looking up errors in C programs, which give the
436: * error a line number. If an argument is present, then
437: * it is the line number, else prompt for a line number
438: * to use.
439: */
1.3 millert 440: /* ARGSUSED */
441: int
1.12 vincent 442: gotoline(int f, int n)
1.1 deraadt 443: {
1.21 deraadt 444: struct line *clp;
1.23 ! kjell 445: char buf[32], *bufp;
! 446: const char *err;
1.1 deraadt 447:
448: if (!(f & FFARG)) {
1.20 kjell 449: if ((bufp = eread("Goto line: ", buf, sizeof(buf),
450: EFNUL | EFNEW | EFCR)) == NULL)
1.18 db 451: return (ABORT);
1.23 ! kjell 452: n = (int)strtonum(buf, INT_MIN, INT_MAX, &err);
! 453: if (err) {
! 454: ewprintf("Line number %s", err);
1.18 db 455: return (FALSE);
1.9 vincent 456: }
1.1 deraadt 457: }
1.5 millert 458: if (n >= 0) {
1.23 ! kjell 459: if (n == 0)
! 460: n++;
! 461: curwp->w_dotline = n;
1.5 millert 462: clp = lforw(curbp->b_linep); /* "clp" is first line */
1.1 deraadt 463: while (--n > 0) {
1.23 ! kjell 464: if (lforw(clp) == curbp->b_linep) {
! 465: curwp->w_dotline = curwp->w_bufp->b_lines;
1.3 millert 466: break;
1.23 ! kjell 467: }
1.1 deraadt 468: clp = lforw(clp);
469: }
470: } else {
1.23 ! kjell 471: curwp->w_dotline = curwp->w_bufp->b_lines + n;
1.5 millert 472: clp = lback(curbp->b_linep); /* "clp" is last line */
1.1 deraadt 473: while (n < 0) {
1.23 ! kjell 474: if (lback(clp) == curbp->b_linep) {
! 475: curwp->w_dotline = 1;
1.3 millert 476: break;
1.23 ! kjell 477: }
1.1 deraadt 478: clp = lback(clp);
479: n++;
480: }
481: }
482: curwp->w_dotp = clp;
483: curwp->w_doto = 0;
484: curwp->w_flag |= WFMOVE;
1.18 db 485: return (TRUE);
1.1 deraadt 486: }