Annotation of src/usr.bin/mg/basic.c, Revision 1.16
1.16 ! vincent 1: /* $OpenBSD: basic.c,v 1.15 2003/09/19 21:20:47 deraadt 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];
1.15 deraadt 242:
243: snprintf(tmp, sizeof tmp, "\\%o", c);
244: col += strlen(tmp);
1.14 vincent 245: }
246: if (col > curgoal)
1.1 deraadt 247: break;
248: }
1.14 vincent 249: return (i);
1.1 deraadt 250: }
251:
252: /*
253: * Scroll forward by a specified number
254: * of lines, or by a full page if no argument.
255: * The "2" is the window overlap (this is the default
256: * value from ITS EMACS). Because the top line in
257: * the window is zapped, we have to do a hard
258: * update and get it back.
259: */
1.3 millert 260: /* ARGSUSED */
261: int
1.12 vincent 262: forwpage(int f, int n)
1.1 deraadt 263: {
1.3 millert 264: LINE *lp;
1.1 deraadt 265:
266: if (!(f & FFARG)) {
1.3 millert 267: n = curwp->w_ntrows - 2; /* Default scroll. */
268: if (n <= 0) /* Forget the overlap */
269: n = 1; /* if tiny window. */
1.1 deraadt 270: } else if (n < 0)
1.3 millert 271: return backpage(f | FFRAND, -n);
1.1 deraadt 272: #ifdef CVMVAS
1.3 millert 273: else /* Convert from pages */
274: n *= curwp->w_ntrows; /* to lines. */
1.1 deraadt 275: #endif
276: lp = curwp->w_linep;
1.3 millert 277: while (n-- && lforw(lp) != curbp->b_linep)
1.1 deraadt 278: lp = lforw(lp);
279: curwp->w_linep = lp;
280: curwp->w_flag |= WFHARD;
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)
284: return TRUE;
285: curwp->w_dotp = curwp->w_linep;
286: curwp->w_doto = 0;
1.1 deraadt 287: return TRUE;
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.3 millert 302: 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.3 millert 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.3 millert 315: while (n-- && lback(lp) != curbp->b_linep)
1.1 deraadt 316: lp = lback(lp);
317: curwp->w_linep = lp;
318: curwp->w_flag |= WFHARD;
319: /* if in current window, don't move dot */
1.3 millert 320: for (n = curwp->w_ntrows; n-- && lp != curbp->b_linep; lp = lforw(lp))
321: if (lp == curwp->w_dotp)
322: return TRUE;
1.1 deraadt 323: curwp->w_dotp = curwp->w_linep;
324: curwp->w_doto = 0;
325: return TRUE;
326: }
327:
1.3 millert 328: /*
329: * These functions are provided for compatibility with Gosling's Emacs. They
330: * are used to scroll the display up (or down) one line at a time.
1.1 deraadt 331: */
1.7 deraadt 332: int
1.12 vincent 333: forw1page(int f, int n)
1.1 deraadt 334: {
1.3 millert 335: if (!(f & FFARG)) {
336: n = 1;
1.1 deraadt 337: f = FFUNIV;
338: }
1.3 millert 339: forwpage(f | FFRAND, n);
1.7 deraadt 340: return TRUE;
1.1 deraadt 341: }
342:
1.7 deraadt 343: int
1.12 vincent 344: back1page(int f, int n)
1.1 deraadt 345: {
346: if (!(f & FFARG)) {
1.3 millert 347: n = 1;
1.1 deraadt 348: f = FFUNIV;
349: }
1.3 millert 350: backpage(f | FFRAND, n);
1.7 deraadt 351: return TRUE;
1.1 deraadt 352: }
353:
354: /*
355: * Page the other window. Check to make sure it exists, then
356: * nextwind, forwpage and restore window pointers.
357: */
1.3 millert 358: int
1.12 vincent 359: pagenext(int f, int n)
1.1 deraadt 360: {
1.3 millert 361: MGWIN *wp;
1.1 deraadt 362:
363: if (wheadp->w_wndp == NULL) {
364: ewprintf("No other window");
365: return FALSE;
366: }
367: wp = curwp;
1.6 art 368: (void) nextwind(f, n);
369: (void) forwpage(f, n);
1.1 deraadt 370: curwp = wp;
371: curbp = wp->w_bufp;
372: return TRUE;
373: }
374:
375: /*
376: * Internal set mark routine, used by other functions (daveb).
377: */
1.6 art 378: void
1.12 vincent 379: isetmark(void)
1.1 deraadt 380: {
381: curwp->w_markp = curwp->w_dotp;
382: curwp->w_marko = curwp->w_doto;
383: }
384:
385: /*
386: * Set the mark in the current window
387: * to the value of dot. A message is written to
388: * the echo line. (ewprintf knows about macros)
389: */
1.3 millert 390: /* ARGSUSED */
391: int
1.12 vincent 392: setmark(int f, int n)
1.1 deraadt 393: {
1.3 millert 394:
1.1 deraadt 395: isetmark();
396: ewprintf("Mark set");
397: return TRUE;
398: }
399:
400: /*
401: * Swap the values of "dot" and "mark" in
402: * the current window. This is pretty easy, because
403: * all of the hard work gets done by the standard routine
404: * that moves the mark about. The only possible
405: * error is "no mark".
406: */
1.3 millert 407: /* ARGSUSED */
408: int
1.12 vincent 409: swapmark(int f, int n)
1.1 deraadt 410: {
1.3 millert 411: LINE *odotp;
412: int odoto;
1.1 deraadt 413:
414: if (curwp->w_markp == NULL) {
415: ewprintf("No mark in this window");
416: return FALSE;
417: }
418: odotp = curwp->w_dotp;
419: odoto = curwp->w_doto;
1.3 millert 420: curwp->w_dotp = curwp->w_markp;
421: curwp->w_doto = curwp->w_marko;
1.1 deraadt 422: curwp->w_markp = odotp;
423: curwp->w_marko = odoto;
424: curwp->w_flag |= WFMOVE;
425: return TRUE;
426: }
427:
428: /*
429: * Go to a specific line, mostly for
430: * looking up errors in C programs, which give the
431: * error a line number. If an argument is present, then
432: * it is the line number, else prompt for a line number
433: * to use.
434: */
1.3 millert 435: /* ARGSUSED */
436: int
1.12 vincent 437: gotoline(int f, int n)
1.1 deraadt 438: {
1.3 millert 439: LINE *clp;
1.16 ! vincent 440: char buf[32], *bufp, *tmp;
1.11 ho 441: long nl;
1.1 deraadt 442:
443: if (!(f & FFARG)) {
1.16 ! vincent 444: if ((bufp = ereply("Goto line: ", buf, sizeof(buf))) == NULL)
! 445: return ABORT;
! 446: else if (bufp[0] == '\0')
! 447: return FALSE;
1.13 vincent 448:
1.16 ! vincent 449: nl = strtol(bufp, &tmp, 10);
! 450: if (bufp[0] == '\0' || *tmp != '\0') {
1.9 vincent 451: ewprintf("Invalid number");
452: return FALSE;
453: }
1.11 ho 454: if (nl >= INT_MAX || nl <= INT_MIN) {
1.9 vincent 455: ewprintf("Out of range");
456: return FALSE;
457: }
1.11 ho 458: n = (int)nl;
1.1 deraadt 459: }
1.5 millert 460: if (n >= 0) {
461: clp = lforw(curbp->b_linep); /* "clp" is first line */
1.1 deraadt 462: while (--n > 0) {
1.3 millert 463: if (lforw(clp) == curbp->b_linep)
464: break;
1.1 deraadt 465: clp = lforw(clp);
466: }
467: } else {
1.5 millert 468: clp = lback(curbp->b_linep); /* "clp" is last line */
1.1 deraadt 469: while (n < 0) {
1.3 millert 470: if (lback(clp) == curbp->b_linep)
471: break;
1.1 deraadt 472: clp = lback(clp);
473: n++;
474: }
475: }
476: curwp->w_dotp = clp;
477: curwp->w_doto = 0;
478: curwp->w_flag |= WFMOVE;
479: return TRUE;
480: }