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