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