Annotation of src/usr.bin/mg/basic.c, Revision 1.27
1.27 ! kjell 1: /* $OpenBSD: basic.c,v 1.26 2006/07/25 08:27:09 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.25 kjell 45: if ((lp = lback(curwp->w_dotp)) == curbp->b_headp) {
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.25 kjell 86: if (curwp->w_dotp == curbp->b_headp) {
1.1 deraadt 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.26 kjell 110: curwp->w_dotp = bfirstlp(curbp);
1.3 millert 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.26 kjell 126: curwp->w_dotp = blastlp(curbp);
1.3 millert 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.25 kjell 148: if ((dlp = curwp->w_dotp) == curbp->b_headp)
1.23 kjell 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.25 kjell 157: if (dlp == curbp->b_headp) {
1.23 kjell 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.25 kjell 191: while (n-- && lback(dlp) != curbp->b_headp) {
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;
1.24 kjell 224: char tmp[5];
225:
1.14 vincent 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 {
1.24 kjell 241: col += snprintf(tmp, sizeof(tmp), "\\%o", c);
1.14 vincent 242: }
243: if (col > curgoal)
1.1 deraadt 244: break;
245: }
1.14 vincent 246: return (i);
1.1 deraadt 247: }
248:
249: /*
250: * Scroll forward by a specified number
251: * of lines, or by a full page if no argument.
252: * The "2" is the window overlap (this is the default
253: * value from ITS EMACS). Because the top line in
254: * the window is zapped, we have to do a hard
255: * update and get it back.
256: */
1.3 millert 257: /* ARGSUSED */
258: int
1.12 vincent 259: forwpage(int f, int n)
1.1 deraadt 260: {
1.21 deraadt 261: struct line *lp;
1.1 deraadt 262:
263: if (!(f & FFARG)) {
1.3 millert 264: n = curwp->w_ntrows - 2; /* Default scroll. */
265: if (n <= 0) /* Forget the overlap */
266: n = 1; /* if tiny window. */
1.1 deraadt 267: } else if (n < 0)
1.18 db 268: return (backpage(f | FFRAND, -n));
1.1 deraadt 269: #ifdef CVMVAS
1.3 millert 270: else /* Convert from pages */
271: n *= curwp->w_ntrows; /* to lines. */
1.1 deraadt 272: #endif
273: lp = curwp->w_linep;
1.25 kjell 274: while (n-- && lforw(lp) != curbp->b_headp) {
1.1 deraadt 275: lp = lforw(lp);
1.23 kjell 276: }
1.1 deraadt 277: curwp->w_linep = lp;
1.22 kjell 278: curwp->w_flag |= WFFULL;
1.1 deraadt 279: /* if in current window, don't move dot */
1.25 kjell 280: for (n = curwp->w_ntrows; n-- && lp != curbp->b_headp; lp = lforw(lp))
1.3 millert 281: if (lp == curwp->w_dotp)
1.18 db 282: return (TRUE);
1.27 ! kjell 283: /* Advance the dot the slow way, for line nos */
! 284: while (curwp->w_dotp != curwp->w_linep) {
! 285: curwp->w_dotp = lforw(curwp->w_dotp);
! 286: curwp->w_dotline++;
! 287: }
1.3 millert 288: curwp->w_doto = 0;
1.18 db 289: return (TRUE);
1.1 deraadt 290: }
291:
292: /*
293: * This command is like "forwpage",
294: * but it goes backwards. The "2", like above,
295: * is the overlap between the two windows. The
296: * value is from the ITS EMACS manual. The
297: * hard update is done because the top line in
298: * the window is zapped.
299: */
1.3 millert 300: /* ARGSUSED */
301: int
1.12 vincent 302: backpage(int f, int n)
1.1 deraadt 303: {
1.21 deraadt 304: struct line *lp;
1.1 deraadt 305:
306: if (!(f & FFARG)) {
1.3 millert 307: n = curwp->w_ntrows - 2; /* Default scroll. */
308: if (n <= 0) /* Don't blow up if the */
309: n = 1; /* window is tiny. */
1.1 deraadt 310: } else if (n < 0)
1.18 db 311: return (forwpage(f | FFRAND, -n));
1.1 deraadt 312: #ifdef CVMVAS
1.3 millert 313: else /* Convert from pages */
314: n *= curwp->w_ntrows; /* to lines. */
1.1 deraadt 315: #endif
316: lp = curwp->w_linep;
1.25 kjell 317: while (n-- && lback(lp) != curbp->b_headp) {
1.1 deraadt 318: lp = lback(lp);
1.23 kjell 319: }
1.1 deraadt 320: curwp->w_linep = lp;
1.22 kjell 321: curwp->w_flag |= WFFULL;
1.1 deraadt 322: /* if in current window, don't move dot */
1.25 kjell 323: for (n = curwp->w_ntrows; n-- && lp != curbp->b_headp; lp = lforw(lp))
1.3 millert 324: if (lp == curwp->w_dotp)
1.18 db 325: return (TRUE);
1.27 ! kjell 326: /* Move the dot the slow way, for line nos */
! 327: while (curwp->w_dotp != curwp->w_linep) {
! 328: curwp->w_dotp = lback(curwp->w_dotp);
! 329: curwp->w_dotline--;
! 330: }
1.1 deraadt 331: curwp->w_doto = 0;
1.18 db 332: return (TRUE);
1.1 deraadt 333: }
334:
1.3 millert 335: /*
336: * These functions are provided for compatibility with Gosling's Emacs. They
337: * are used to scroll the display up (or down) one line at a time.
1.1 deraadt 338: */
1.7 deraadt 339: int
1.12 vincent 340: forw1page(int f, int n)
1.1 deraadt 341: {
1.3 millert 342: if (!(f & FFARG)) {
343: n = 1;
1.1 deraadt 344: f = FFUNIV;
345: }
1.3 millert 346: forwpage(f | FFRAND, n);
1.18 db 347: return (TRUE);
1.1 deraadt 348: }
349:
1.7 deraadt 350: int
1.12 vincent 351: back1page(int f, int n)
1.1 deraadt 352: {
353: if (!(f & FFARG)) {
1.3 millert 354: n = 1;
1.1 deraadt 355: f = FFUNIV;
356: }
1.3 millert 357: backpage(f | FFRAND, n);
1.18 db 358: return (TRUE);
1.1 deraadt 359: }
360:
361: /*
362: * Page the other window. Check to make sure it exists, then
363: * nextwind, forwpage and restore window pointers.
364: */
1.3 millert 365: int
1.12 vincent 366: pagenext(int f, int n)
1.1 deraadt 367: {
1.21 deraadt 368: struct mgwin *wp;
1.1 deraadt 369:
370: if (wheadp->w_wndp == NULL) {
371: ewprintf("No other window");
1.18 db 372: return (FALSE);
1.1 deraadt 373: }
374: wp = curwp;
1.6 art 375: (void) nextwind(f, n);
376: (void) forwpage(f, n);
1.1 deraadt 377: curwp = wp;
378: curbp = wp->w_bufp;
1.18 db 379: return (TRUE);
1.1 deraadt 380: }
381:
382: /*
383: * Internal set mark routine, used by other functions (daveb).
384: */
1.6 art 385: void
1.12 vincent 386: isetmark(void)
1.1 deraadt 387: {
388: curwp->w_markp = curwp->w_dotp;
389: curwp->w_marko = curwp->w_doto;
1.23 kjell 390: curwp->w_markline = curwp->w_dotline;
1.1 deraadt 391: }
392:
393: /*
394: * Set the mark in the current window
395: * to the value of dot. A message is written to
396: * the echo line. (ewprintf knows about macros)
397: */
1.3 millert 398: /* ARGSUSED */
399: int
1.12 vincent 400: setmark(int f, int n)
1.1 deraadt 401: {
402: isetmark();
403: ewprintf("Mark set");
1.18 db 404: return (TRUE);
1.1 deraadt 405: }
406:
407: /*
408: * Swap the values of "dot" and "mark" in
409: * the current window. This is pretty easy, because
410: * all of the hard work gets done by the standard routine
411: * that moves the mark about. The only possible
412: * error is "no mark".
413: */
1.3 millert 414: /* ARGSUSED */
415: int
1.12 vincent 416: swapmark(int f, int n)
1.1 deraadt 417: {
1.21 deraadt 418: struct line *odotp;
1.23 kjell 419: int odoto, odotline;
1.1 deraadt 420:
421: if (curwp->w_markp == NULL) {
422: ewprintf("No mark in this window");
1.18 db 423: return (FALSE);
1.1 deraadt 424: }
425: odotp = curwp->w_dotp;
426: odoto = curwp->w_doto;
1.23 kjell 427: odotline = curwp->w_dotline;
1.3 millert 428: curwp->w_dotp = curwp->w_markp;
429: curwp->w_doto = curwp->w_marko;
1.23 kjell 430: curwp->w_dotline = curwp->w_markline;
1.1 deraadt 431: curwp->w_markp = odotp;
432: curwp->w_marko = odoto;
1.23 kjell 433: curwp->w_markline = odotline;
1.1 deraadt 434: curwp->w_flag |= WFMOVE;
1.18 db 435: return (TRUE);
1.1 deraadt 436: }
437:
438: /*
439: * Go to a specific line, mostly for
440: * looking up errors in C programs, which give the
441: * error a line number. If an argument is present, then
442: * it is the line number, else prompt for a line number
443: * to use.
444: */
1.3 millert 445: /* ARGSUSED */
446: int
1.12 vincent 447: gotoline(int f, int n)
1.1 deraadt 448: {
1.21 deraadt 449: struct line *clp;
1.23 kjell 450: char buf[32], *bufp;
451: const char *err;
1.1 deraadt 452:
453: if (!(f & FFARG)) {
1.20 kjell 454: if ((bufp = eread("Goto line: ", buf, sizeof(buf),
455: EFNUL | EFNEW | EFCR)) == NULL)
1.24 kjell 456: return (ABORT);
457: if (bufp[0] == '\0')
1.18 db 458: return (ABORT);
1.23 kjell 459: n = (int)strtonum(buf, INT_MIN, INT_MAX, &err);
460: if (err) {
461: ewprintf("Line number %s", err);
1.18 db 462: return (FALSE);
1.9 vincent 463: }
1.1 deraadt 464: }
1.5 millert 465: if (n >= 0) {
1.23 kjell 466: if (n == 0)
467: n++;
468: curwp->w_dotline = n;
1.25 kjell 469: clp = lforw(curbp->b_headp); /* "clp" is first line */
1.1 deraadt 470: while (--n > 0) {
1.25 kjell 471: if (lforw(clp) == curbp->b_headp) {
1.23 kjell 472: curwp->w_dotline = curwp->w_bufp->b_lines;
1.3 millert 473: break;
1.23 kjell 474: }
1.1 deraadt 475: clp = lforw(clp);
476: }
477: } else {
1.23 kjell 478: curwp->w_dotline = curwp->w_bufp->b_lines + n;
1.25 kjell 479: clp = lback(curbp->b_headp); /* "clp" is last line */
1.1 deraadt 480: while (n < 0) {
1.25 kjell 481: if (lback(clp) == curbp->b_headp) {
1.23 kjell 482: curwp->w_dotline = 1;
1.3 millert 483: break;
1.23 kjell 484: }
1.1 deraadt 485: clp = lback(clp);
486: n++;
487: }
488: }
489: curwp->w_dotp = clp;
490: curwp->w_doto = 0;
491: curwp->w_flag |= WFMOVE;
1.18 db 492: return (TRUE);
1.1 deraadt 493: }