Annotation of src/usr.bin/mg/basic.c, Revision 1.14
1.14 ! vincent 1: /* $OpenBSD: basic.c,v 1.13 2002/03/11 13:08:51 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.14 ! vincent 14: #include <ctype.h>
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);
1.14 ! vincent 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);
1.14 ! vincent 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.14 ! vincent 211: curgoal = getcolpos(); /* Get the position. */
1.3 millert 212: /* we can now display past end of display, don't chop! */
1.1 deraadt 213: }
214:
215: /*
216: * This routine looks at a line (pointed
217: * to by the LINE pointer "dlp") and the current
218: * vertical motion goal column (set by the "setgoal"
219: * routine above) and returns the best offset to use
220: * when a vertical motion is made into the line.
221: */
1.3 millert 222: int
1.12 vincent 223: getgoal(LINE *dlp)
1.3 millert 224: {
1.14 ! vincent 225: int c, i, col = 0;
! 226:
! 227: for (i = 0; i < llength(dlp); i++) {
! 228: c = lgetc(dlp, i);
1.1 deraadt 229: if (c == '\t'
230: #ifdef NOTAB
1.3 millert 231: && !(curbp->b_flag & BFNOTAB)
1.1 deraadt 232: #endif
1.14 ! vincent 233: ) {
! 234: col |= 0x07;
! 235: col++;
! 236: } else if (ISCTRL(c) != FALSE) {
! 237: col += 2;
! 238: } else if (isprint(c))
! 239: col++;
! 240: else {
! 241: char tmp[5];
! 242: col += snprintf(tmp, sizeof tmp, "\\%o",
! 243: c);
! 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.3 millert 263: 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.3 millert 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;
279: curwp->w_flag |= WFHARD;
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)
283: return TRUE;
284: curwp->w_dotp = curwp->w_linep;
285: curwp->w_doto = 0;
1.1 deraadt 286: return TRUE;
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.3 millert 301: 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.3 millert 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;
317: curwp->w_flag |= WFHARD;
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)
321: return TRUE;
1.1 deraadt 322: curwp->w_dotp = curwp->w_linep;
323: curwp->w_doto = 0;
324: return TRUE;
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.7 deraadt 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.7 deraadt 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.3 millert 360: MGWIN *wp;
1.1 deraadt 361:
362: if (wheadp->w_wndp == NULL) {
363: ewprintf("No other window");
364: return FALSE;
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;
371: return TRUE;
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: {
1.3 millert 393:
1.1 deraadt 394: isetmark();
395: ewprintf("Mark set");
396: return TRUE;
397: }
398:
399: /*
400: * Swap the values of "dot" and "mark" in
401: * the current window. This is pretty easy, because
402: * all of the hard work gets done by the standard routine
403: * that moves the mark about. The only possible
404: * error is "no mark".
405: */
1.3 millert 406: /* ARGSUSED */
407: int
1.12 vincent 408: swapmark(int f, int n)
1.1 deraadt 409: {
1.3 millert 410: LINE *odotp;
411: int odoto;
1.1 deraadt 412:
413: if (curwp->w_markp == NULL) {
414: ewprintf("No mark in this window");
415: return FALSE;
416: }
417: odotp = curwp->w_dotp;
418: odoto = curwp->w_doto;
1.3 millert 419: curwp->w_dotp = curwp->w_markp;
420: curwp->w_doto = curwp->w_marko;
1.1 deraadt 421: curwp->w_markp = odotp;
422: curwp->w_marko = odoto;
423: curwp->w_flag |= WFMOVE;
424: return TRUE;
425: }
426:
427: /*
428: * Go to a specific line, mostly for
429: * looking up errors in C programs, which give the
430: * error a line number. If an argument is present, then
431: * it is the line number, else prompt for a line number
432: * to use.
433: */
1.3 millert 434: /* ARGSUSED */
435: int
1.12 vincent 436: gotoline(int f, int n)
1.1 deraadt 437: {
1.3 millert 438: LINE *clp;
439: int s;
1.11 ho 440: char buf[32], *tmp;
441: long nl;
1.1 deraadt 442:
443: if (!(f & FFARG)) {
1.3 millert 444: if ((s = ereply("Goto line: ", buf, sizeof(buf))) != TRUE)
1.1 deraadt 445: return s;
1.13 vincent 446:
1.11 ho 447: nl = strtol(buf, &tmp, 10);
1.9 vincent 448: if (buf[0] == '\0' || *tmp != '\0') {
449: ewprintf("Invalid number");
450: return FALSE;
451: }
1.11 ho 452: if (nl >= INT_MAX || nl <= INT_MIN) {
1.9 vincent 453: ewprintf("Out of range");
454: return FALSE;
455: }
1.11 ho 456: n = (int)nl;
1.1 deraadt 457: }
1.5 millert 458: if (n >= 0) {
459: clp = lforw(curbp->b_linep); /* "clp" is first line */
1.1 deraadt 460: while (--n > 0) {
1.3 millert 461: if (lforw(clp) == curbp->b_linep)
462: break;
1.1 deraadt 463: clp = lforw(clp);
464: }
465: } else {
1.5 millert 466: clp = lback(curbp->b_linep); /* "clp" is last line */
1.1 deraadt 467: while (n < 0) {
1.3 millert 468: if (lback(clp) == curbp->b_linep)
469: break;
1.1 deraadt 470: clp = lback(clp);
471: n++;
472: }
473: }
474: curwp->w_dotp = clp;
475: curwp->w_doto = 0;
476: curwp->w_flag |= WFMOVE;
477: return TRUE;
478: }