Annotation of src/usr.bin/mg/basic.c, Revision 1.36
1.36 ! lum 1: /* $OpenBSD: basic.c,v 1.35 2012/06/08 05:10:50 lum 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.30 kjell 52: curwp->w_rflag |= 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.30 kjell 94: curwp->w_rflag |= WFMOVE;
1.1 deraadt 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.30 kjell 112: curwp->w_rflag |= 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.30 kjell 129: curwp->w_rflag |= 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);
1.30 kjell 160: curwp->w_rflag |= WFMOVE;
1.23 kjell 161: return (TRUE);
1.1 deraadt 162: }
1.23 kjell 163: curwp->w_dotline++;
1.1 deraadt 164: }
1.30 kjell 165: curwp->w_rflag |= WFMOVE;
1.23 kjell 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.30 kjell 197: curwp->w_rflag |= 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.31 lum 269:
1.1 deraadt 270: lp = curwp->w_linep;
1.31 lum 271: while (n--)
1.34 lum 272: if ((lp = lforw(lp)) == curbp->b_headp) {
273: ttbeep();
274: ewprintf("End of buffer");
1.31 lum 275: return(TRUE);
1.34 lum 276: }
1.31 lum 277:
1.1 deraadt 278: curwp->w_linep = lp;
1.30 kjell 279: curwp->w_rflag |= WFFULL;
1.31 lum 280:
1.1 deraadt 281: /* if in current window, don't move dot */
1.32 lum 282: for (n = curwp->w_ntrows; n-- && lp != curbp->b_headp; lp = lforw(lp))
1.3 millert 283: if (lp == curwp->w_dotp)
1.18 db 284: return (TRUE);
1.31 lum 285:
1.27 kjell 286: /* Advance the dot the slow way, for line nos */
287: while (curwp->w_dotp != curwp->w_linep) {
288: curwp->w_dotp = lforw(curwp->w_dotp);
289: curwp->w_dotline++;
290: }
1.3 millert 291: curwp->w_doto = 0;
1.18 db 292: return (TRUE);
1.1 deraadt 293: }
294:
295: /*
296: * This command is like "forwpage",
297: * but it goes backwards. The "2", like above,
298: * is the overlap between the two windows. The
299: * value is from the ITS EMACS manual. The
300: * hard update is done because the top line in
301: * the window is zapped.
302: */
1.3 millert 303: /* ARGSUSED */
304: int
1.12 vincent 305: backpage(int f, int n)
1.1 deraadt 306: {
1.33 lum 307: struct line *lp, *lp2;
1.1 deraadt 308:
309: if (!(f & FFARG)) {
1.3 millert 310: n = curwp->w_ntrows - 2; /* Default scroll. */
311: if (n <= 0) /* Don't blow up if the */
1.35 lum 312: return (backline(f, 1));/* window is tiny. */
1.1 deraadt 313: } else if (n < 0)
1.18 db 314: return (forwpage(f | FFRAND, -n));
1.33 lum 315:
316: lp = lp2 = curwp->w_linep;
317:
1.25 kjell 318: while (n-- && lback(lp) != curbp->b_headp) {
1.1 deraadt 319: lp = lback(lp);
1.34 lum 320: }
321: if (lp == curwp->w_linep) {
322: ttbeep();
323: ewprintf("Beginning of buffer");
1.23 kjell 324: }
1.1 deraadt 325: curwp->w_linep = lp;
1.30 kjell 326: curwp->w_rflag |= WFFULL;
1.33 lum 327:
1.1 deraadt 328: /* if in current window, don't move dot */
1.25 kjell 329: for (n = curwp->w_ntrows; n-- && lp != curbp->b_headp; lp = lforw(lp))
1.3 millert 330: if (lp == curwp->w_dotp)
1.18 db 331: return (TRUE);
1.33 lum 332:
333: lp2 = lforw(lp2);
334:
1.27 kjell 335: /* Move the dot the slow way, for line nos */
1.33 lum 336: while (curwp->w_dotp != lp2) {
1.36 ! lum 337: if (curwp->w_dotline <= curwp->w_ntrows)
! 338: return (TRUE);
1.27 kjell 339: curwp->w_dotp = lback(curwp->w_dotp);
340: curwp->w_dotline--;
341: }
1.1 deraadt 342: curwp->w_doto = 0;
1.18 db 343: return (TRUE);
1.1 deraadt 344: }
345:
1.3 millert 346: /*
347: * These functions are provided for compatibility with Gosling's Emacs. They
348: * are used to scroll the display up (or down) one line at a time.
1.1 deraadt 349: */
1.7 deraadt 350: int
1.12 vincent 351: forw1page(int f, int n)
1.1 deraadt 352: {
1.3 millert 353: if (!(f & FFARG)) {
354: n = 1;
1.1 deraadt 355: f = FFUNIV;
356: }
1.3 millert 357: forwpage(f | FFRAND, n);
1.18 db 358: return (TRUE);
1.1 deraadt 359: }
360:
1.7 deraadt 361: int
1.12 vincent 362: back1page(int f, int n)
1.1 deraadt 363: {
364: if (!(f & FFARG)) {
1.3 millert 365: n = 1;
1.1 deraadt 366: f = FFUNIV;
367: }
1.3 millert 368: backpage(f | FFRAND, n);
1.18 db 369: return (TRUE);
1.1 deraadt 370: }
371:
372: /*
373: * Page the other window. Check to make sure it exists, then
374: * nextwind, forwpage and restore window pointers.
375: */
1.3 millert 376: int
1.12 vincent 377: pagenext(int f, int n)
1.1 deraadt 378: {
1.21 deraadt 379: struct mgwin *wp;
1.1 deraadt 380:
381: if (wheadp->w_wndp == NULL) {
382: ewprintf("No other window");
1.18 db 383: return (FALSE);
1.1 deraadt 384: }
385: wp = curwp;
1.6 art 386: (void) nextwind(f, n);
387: (void) forwpage(f, n);
1.1 deraadt 388: curwp = wp;
389: curbp = wp->w_bufp;
1.18 db 390: return (TRUE);
1.1 deraadt 391: }
392:
393: /*
394: * Internal set mark routine, used by other functions (daveb).
395: */
1.6 art 396: void
1.12 vincent 397: isetmark(void)
1.1 deraadt 398: {
399: curwp->w_markp = curwp->w_dotp;
400: curwp->w_marko = curwp->w_doto;
1.23 kjell 401: curwp->w_markline = curwp->w_dotline;
1.1 deraadt 402: }
403:
404: /*
405: * Set the mark in the current window
406: * to the value of dot. A message is written to
407: * the echo line. (ewprintf knows about macros)
408: */
1.3 millert 409: /* ARGSUSED */
410: int
1.12 vincent 411: setmark(int f, int n)
1.1 deraadt 412: {
413: isetmark();
414: ewprintf("Mark set");
1.29 kjell 415: return (TRUE);
416: }
417:
418: /* Clear the mark, if set. */
419: /* ARGSUSED */
420: int
421: clearmark(int f, int n)
422: {
423: if (!curwp->w_markp)
424: return (FALSE);
425:
426: curwp->w_markp = NULL;
427: curwp->w_marko = 0;
428: curwp->w_markline = 0;
429:
1.18 db 430: return (TRUE);
1.1 deraadt 431: }
432:
433: /*
434: * Swap the values of "dot" and "mark" in
435: * the current window. This is pretty easy, because
436: * all of the hard work gets done by the standard routine
437: * that moves the mark about. The only possible
438: * error is "no mark".
439: */
1.3 millert 440: /* ARGSUSED */
441: int
1.12 vincent 442: swapmark(int f, int n)
1.1 deraadt 443: {
1.21 deraadt 444: struct line *odotp;
1.23 kjell 445: int odoto, odotline;
1.1 deraadt 446:
447: if (curwp->w_markp == NULL) {
448: ewprintf("No mark in this window");
1.18 db 449: return (FALSE);
1.1 deraadt 450: }
451: odotp = curwp->w_dotp;
452: odoto = curwp->w_doto;
1.23 kjell 453: odotline = curwp->w_dotline;
1.3 millert 454: curwp->w_dotp = curwp->w_markp;
455: curwp->w_doto = curwp->w_marko;
1.23 kjell 456: curwp->w_dotline = curwp->w_markline;
1.1 deraadt 457: curwp->w_markp = odotp;
458: curwp->w_marko = odoto;
1.23 kjell 459: curwp->w_markline = odotline;
1.30 kjell 460: curwp->w_rflag |= WFMOVE;
1.18 db 461: return (TRUE);
1.1 deraadt 462: }
463:
464: /*
465: * Go to a specific line, mostly for
466: * looking up errors in C programs, which give the
467: * error a line number. If an argument is present, then
468: * it is the line number, else prompt for a line number
469: * to use.
470: */
1.3 millert 471: /* ARGSUSED */
472: int
1.12 vincent 473: gotoline(int f, int n)
1.1 deraadt 474: {
1.21 deraadt 475: struct line *clp;
1.23 kjell 476: char buf[32], *bufp;
477: const char *err;
1.1 deraadt 478:
479: if (!(f & FFARG)) {
1.20 kjell 480: if ((bufp = eread("Goto line: ", buf, sizeof(buf),
481: EFNUL | EFNEW | EFCR)) == NULL)
1.24 kjell 482: return (ABORT);
483: if (bufp[0] == '\0')
1.18 db 484: return (ABORT);
1.23 kjell 485: n = (int)strtonum(buf, INT_MIN, INT_MAX, &err);
486: if (err) {
487: ewprintf("Line number %s", err);
1.18 db 488: return (FALSE);
1.9 vincent 489: }
1.1 deraadt 490: }
1.5 millert 491: if (n >= 0) {
1.23 kjell 492: if (n == 0)
493: n++;
494: curwp->w_dotline = n;
1.25 kjell 495: clp = lforw(curbp->b_headp); /* "clp" is first line */
1.1 deraadt 496: while (--n > 0) {
1.25 kjell 497: if (lforw(clp) == curbp->b_headp) {
1.23 kjell 498: curwp->w_dotline = curwp->w_bufp->b_lines;
1.3 millert 499: break;
1.23 kjell 500: }
1.1 deraadt 501: clp = lforw(clp);
502: }
503: } else {
1.23 kjell 504: curwp->w_dotline = curwp->w_bufp->b_lines + n;
1.25 kjell 505: clp = lback(curbp->b_headp); /* "clp" is last line */
1.1 deraadt 506: while (n < 0) {
1.25 kjell 507: if (lback(clp) == curbp->b_headp) {
1.23 kjell 508: curwp->w_dotline = 1;
1.3 millert 509: break;
1.23 kjell 510: }
1.1 deraadt 511: clp = lback(clp);
512: n++;
513: }
514: }
515: curwp->w_dotp = clp;
516: curwp->w_doto = 0;
1.30 kjell 517: curwp->w_rflag |= WFMOVE;
1.18 db 518: return (TRUE);
1.1 deraadt 519: }