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