Annotation of src/usr.bin/mg/basic.c, Revision 1.34
1.34 ! lum 1: /* $OpenBSD: basic.c,v 1.33 2012/05/31 10:55:53 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 */
312: n = 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.27 kjell 337: curwp->w_dotp = lback(curwp->w_dotp);
338: curwp->w_dotline--;
339: }
1.1 deraadt 340: curwp->w_doto = 0;
1.18 db 341: return (TRUE);
1.1 deraadt 342: }
343:
1.3 millert 344: /*
345: * These functions are provided for compatibility with Gosling's Emacs. They
346: * are used to scroll the display up (or down) one line at a time.
1.1 deraadt 347: */
1.7 deraadt 348: int
1.12 vincent 349: forw1page(int f, int n)
1.1 deraadt 350: {
1.3 millert 351: if (!(f & FFARG)) {
352: n = 1;
1.1 deraadt 353: f = FFUNIV;
354: }
1.3 millert 355: forwpage(f | FFRAND, n);
1.18 db 356: return (TRUE);
1.1 deraadt 357: }
358:
1.7 deraadt 359: int
1.12 vincent 360: back1page(int f, int n)
1.1 deraadt 361: {
362: if (!(f & FFARG)) {
1.3 millert 363: n = 1;
1.1 deraadt 364: f = FFUNIV;
365: }
1.3 millert 366: backpage(f | FFRAND, n);
1.18 db 367: return (TRUE);
1.1 deraadt 368: }
369:
370: /*
371: * Page the other window. Check to make sure it exists, then
372: * nextwind, forwpage and restore window pointers.
373: */
1.3 millert 374: int
1.12 vincent 375: pagenext(int f, int n)
1.1 deraadt 376: {
1.21 deraadt 377: struct mgwin *wp;
1.1 deraadt 378:
379: if (wheadp->w_wndp == NULL) {
380: ewprintf("No other window");
1.18 db 381: return (FALSE);
1.1 deraadt 382: }
383: wp = curwp;
1.6 art 384: (void) nextwind(f, n);
385: (void) forwpage(f, n);
1.1 deraadt 386: curwp = wp;
387: curbp = wp->w_bufp;
1.18 db 388: return (TRUE);
1.1 deraadt 389: }
390:
391: /*
392: * Internal set mark routine, used by other functions (daveb).
393: */
1.6 art 394: void
1.12 vincent 395: isetmark(void)
1.1 deraadt 396: {
397: curwp->w_markp = curwp->w_dotp;
398: curwp->w_marko = curwp->w_doto;
1.23 kjell 399: curwp->w_markline = curwp->w_dotline;
1.1 deraadt 400: }
401:
402: /*
403: * Set the mark in the current window
404: * to the value of dot. A message is written to
405: * the echo line. (ewprintf knows about macros)
406: */
1.3 millert 407: /* ARGSUSED */
408: int
1.12 vincent 409: setmark(int f, int n)
1.1 deraadt 410: {
411: isetmark();
412: ewprintf("Mark set");
1.29 kjell 413: return (TRUE);
414: }
415:
416: /* Clear the mark, if set. */
417: /* ARGSUSED */
418: int
419: clearmark(int f, int n)
420: {
421: if (!curwp->w_markp)
422: return (FALSE);
423:
424: curwp->w_markp = NULL;
425: curwp->w_marko = 0;
426: curwp->w_markline = 0;
427:
1.18 db 428: return (TRUE);
1.1 deraadt 429: }
430:
431: /*
432: * Swap the values of "dot" and "mark" in
433: * the current window. This is pretty easy, because
434: * all of the hard work gets done by the standard routine
435: * that moves the mark about. The only possible
436: * error is "no mark".
437: */
1.3 millert 438: /* ARGSUSED */
439: int
1.12 vincent 440: swapmark(int f, int n)
1.1 deraadt 441: {
1.21 deraadt 442: struct line *odotp;
1.23 kjell 443: int odoto, odotline;
1.1 deraadt 444:
445: if (curwp->w_markp == NULL) {
446: ewprintf("No mark in this window");
1.18 db 447: return (FALSE);
1.1 deraadt 448: }
449: odotp = curwp->w_dotp;
450: odoto = curwp->w_doto;
1.23 kjell 451: odotline = curwp->w_dotline;
1.3 millert 452: curwp->w_dotp = curwp->w_markp;
453: curwp->w_doto = curwp->w_marko;
1.23 kjell 454: curwp->w_dotline = curwp->w_markline;
1.1 deraadt 455: curwp->w_markp = odotp;
456: curwp->w_marko = odoto;
1.23 kjell 457: curwp->w_markline = odotline;
1.30 kjell 458: curwp->w_rflag |= WFMOVE;
1.18 db 459: return (TRUE);
1.1 deraadt 460: }
461:
462: /*
463: * Go to a specific line, mostly for
464: * looking up errors in C programs, which give the
465: * error a line number. If an argument is present, then
466: * it is the line number, else prompt for a line number
467: * to use.
468: */
1.3 millert 469: /* ARGSUSED */
470: int
1.12 vincent 471: gotoline(int f, int n)
1.1 deraadt 472: {
1.21 deraadt 473: struct line *clp;
1.23 kjell 474: char buf[32], *bufp;
475: const char *err;
1.1 deraadt 476:
477: if (!(f & FFARG)) {
1.20 kjell 478: if ((bufp = eread("Goto line: ", buf, sizeof(buf),
479: EFNUL | EFNEW | EFCR)) == NULL)
1.24 kjell 480: return (ABORT);
481: if (bufp[0] == '\0')
1.18 db 482: return (ABORT);
1.23 kjell 483: n = (int)strtonum(buf, INT_MIN, INT_MAX, &err);
484: if (err) {
485: ewprintf("Line number %s", err);
1.18 db 486: return (FALSE);
1.9 vincent 487: }
1.1 deraadt 488: }
1.5 millert 489: if (n >= 0) {
1.23 kjell 490: if (n == 0)
491: n++;
492: curwp->w_dotline = n;
1.25 kjell 493: clp = lforw(curbp->b_headp); /* "clp" is first line */
1.1 deraadt 494: while (--n > 0) {
1.25 kjell 495: if (lforw(clp) == curbp->b_headp) {
1.23 kjell 496: curwp->w_dotline = curwp->w_bufp->b_lines;
1.3 millert 497: break;
1.23 kjell 498: }
1.1 deraadt 499: clp = lforw(clp);
500: }
501: } else {
1.23 kjell 502: curwp->w_dotline = curwp->w_bufp->b_lines + n;
1.25 kjell 503: clp = lback(curbp->b_headp); /* "clp" is last line */
1.1 deraadt 504: while (n < 0) {
1.25 kjell 505: if (lback(clp) == curbp->b_headp) {
1.23 kjell 506: curwp->w_dotline = 1;
1.3 millert 507: break;
1.23 kjell 508: }
1.1 deraadt 509: clp = lback(clp);
510: n++;
511: }
512: }
513: curwp->w_dotp = clp;
514: curwp->w_doto = 0;
1.30 kjell 515: curwp->w_rflag |= WFMOVE;
1.18 db 516: return (TRUE);
1.1 deraadt 517: }