Annotation of src/usr.bin/mg/basic.c, Revision 1.40
1.40 ! lum 1: /* $OpenBSD: basic.c,v 1.39 2013/03/25 11:41:44 florian 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.40 ! lum 46: if (!(f & FFRAND)) {
! 47: dobeep();
1.1 deraadt 48: ewprintf("Beginning of buffer");
1.40 ! lum 49: }
1.1 deraadt 50: return (FALSE);
51: }
1.3 millert 52: curwp->w_dotp = lp;
53: curwp->w_doto = llength(lp);
1.30 kjell 54: curwp->w_rflag |= WFMOVE;
1.23 kjell 55: curwp->w_dotline--;
1.1 deraadt 56: } else
57: curwp->w_doto--;
58: }
1.18 db 59: return (TRUE);
1.1 deraadt 60: }
61:
62: /*
63: * Go to end of line.
64: */
1.3 millert 65: /* ARGSUSED */
66: int
1.12 vincent 67: gotoeol(int f, int n)
1.1 deraadt 68: {
1.3 millert 69: curwp->w_doto = llength(curwp->w_dotp);
1.1 deraadt 70: return (TRUE);
71: }
72:
73: /*
74: * Move cursor forwards. Do the
75: * right thing if the count is less than
76: * 0. Error if you try to move forward
77: * from the end of the buffer.
78: */
1.3 millert 79: /* ARGSUSED */
80: int
1.12 vincent 81: forwchar(int f, int n)
1.1 deraadt 82: {
1.3 millert 83: if (n < 0)
1.18 db 84: return (backchar(f, -n));
1.1 deraadt 85: while (n--) {
86: if (curwp->w_doto == llength(curwp->w_dotp)) {
1.3 millert 87: curwp->w_dotp = lforw(curwp->w_dotp);
1.25 kjell 88: if (curwp->w_dotp == curbp->b_headp) {
1.1 deraadt 89: curwp->w_dotp = lback(curwp->w_dotp);
1.40 ! lum 90: if (!(f & FFRAND)) {
! 91: dobeep();
1.1 deraadt 92: ewprintf("End of buffer");
1.40 ! lum 93: }
1.18 db 94: return (FALSE);
1.1 deraadt 95: }
1.3 millert 96: curwp->w_doto = 0;
1.23 kjell 97: curwp->w_dotline++;
1.30 kjell 98: curwp->w_rflag |= WFMOVE;
1.1 deraadt 99: } else
100: curwp->w_doto++;
101: }
1.18 db 102: return (TRUE);
1.1 deraadt 103: }
104:
105: /*
106: * Go to the beginning of the
1.22 kjell 107: * buffer. Setting WFFULL is conservative,
1.1 deraadt 108: * but almost always the case.
109: */
1.3 millert 110: int
1.12 vincent 111: gotobob(int f, int n)
1.1 deraadt 112: {
1.6 art 113: (void) setmark(f, n);
1.26 kjell 114: curwp->w_dotp = bfirstlp(curbp);
1.3 millert 115: curwp->w_doto = 0;
1.30 kjell 116: curwp->w_rflag |= WFFULL;
1.23 kjell 117: curwp->w_dotline = 1;
1.18 db 118: return (TRUE);
1.1 deraadt 119: }
120:
121: /*
1.37 lum 122: * Go to the end of the buffer. Leave dot 3 lines from the bottom of the
123: * window if buffer length is longer than window length; same as emacs.
124: * Setting WFFULL is conservative, but almost always the case.
1.1 deraadt 125: */
1.3 millert 126: int
1.12 vincent 127: gotoeob(int f, int n)
1.1 deraadt 128: {
1.37 lum 129: struct line *lp;
130:
1.6 art 131: (void) setmark(f, n);
1.26 kjell 132: curwp->w_dotp = blastlp(curbp);
1.3 millert 133: curwp->w_doto = llength(curwp->w_dotp);
1.23 kjell 134: curwp->w_dotline = curwp->w_bufp->b_lines;
1.37 lum 135:
136: lp = curwp->w_dotp;
137: n = curwp->w_ntrows - 3;
138:
139: if (n < curwp->w_bufp->b_lines && n >= 3) {
140: while (n--)
141: curwp->w_dotp = lback(curwp->w_dotp);
142:
143: curwp->w_linep = curwp->w_dotp;
144: curwp->w_dotp = lp;
145: }
1.30 kjell 146: curwp->w_rflag |= WFFULL;
1.18 db 147: return (TRUE);
1.1 deraadt 148: }
149:
150: /*
151: * Move forward by full lines.
152: * If the number of lines to move is less
153: * than zero, call the backward line function to
154: * actually do it. The last command controls how
155: * the goal column is set.
156: */
1.3 millert 157: /* ARGSUSED */
158: int
1.12 vincent 159: forwline(int f, int n)
1.1 deraadt 160: {
1.21 deraadt 161: struct line *dlp;
1.1 deraadt 162:
163: if (n < 0)
1.18 db 164: return (backline(f | FFRAND, -n));
1.25 kjell 165: if ((dlp = curwp->w_dotp) == curbp->b_headp)
1.23 kjell 166: return(TRUE);
1.14 vincent 167: if ((lastflag & CFCPCN) == 0) /* Fix goal. */
1.1 deraadt 168: setgoal();
169: thisflag |= CFCPCN;
1.3 millert 170: if (n == 0)
1.18 db 171: return (TRUE);
1.23 kjell 172: while (n--) {
1.1 deraadt 173: dlp = lforw(dlp);
1.25 kjell 174: if (dlp == curbp->b_headp) {
1.23 kjell 175: curwp->w_dotp = lback(dlp);
176: curwp->w_doto = llength(curwp->w_dotp);
1.30 kjell 177: curwp->w_rflag |= WFMOVE;
1.23 kjell 178: return (TRUE);
1.1 deraadt 179: }
1.23 kjell 180: curwp->w_dotline++;
1.1 deraadt 181: }
1.30 kjell 182: curwp->w_rflag |= WFMOVE;
1.23 kjell 183: curwp->w_dotp = dlp;
184: curwp->w_doto = getgoal(dlp);
185:
1.18 db 186: return (TRUE);
1.1 deraadt 187: }
188:
189: /*
190: * This function is like "forwline", but
191: * goes backwards. The scheme is exactly the same.
192: * Check for arguments that are less than zero and
193: * call your alternate. Figure out the new line and
194: * call "movedot" to perform the motion.
195: */
1.3 millert 196: /* ARGSUSED */
197: int
1.12 vincent 198: backline(int f, int n)
1.1 deraadt 199: {
1.21 deraadt 200: struct line *dlp;
1.1 deraadt 201:
1.3 millert 202: if (n < 0)
1.18 db 203: return (forwline(f | FFRAND, -n));
1.14 vincent 204: if ((lastflag & CFCPCN) == 0) /* Fix goal. */
1.1 deraadt 205: setgoal();
206: thisflag |= CFCPCN;
207: dlp = curwp->w_dotp;
1.25 kjell 208: while (n-- && lback(dlp) != curbp->b_headp) {
1.1 deraadt 209: dlp = lback(dlp);
1.23 kjell 210: curwp->w_dotline--;
211: }
1.3 millert 212: curwp->w_dotp = dlp;
213: curwp->w_doto = getgoal(dlp);
1.30 kjell 214: curwp->w_rflag |= WFMOVE;
1.18 db 215: return (TRUE);
1.1 deraadt 216: }
217:
218: /*
1.3 millert 219: * Set the current goal column, which is saved in the external variable
220: * "curgoal", to the current cursor column. The column is never off
221: * the edge of the screen; it's more like display then show position.
1.1 deraadt 222: */
1.6 art 223: void
1.12 vincent 224: setgoal(void)
1.3 millert 225: {
1.39 florian 226: curgoal = getcolpos(curwp); /* Get the position. */
1.3 millert 227: /* we can now display past end of display, don't chop! */
1.1 deraadt 228: }
229:
230: /*
231: * This routine looks at a line (pointed
232: * to by the LINE pointer "dlp") and the current
233: * vertical motion goal column (set by the "setgoal"
234: * routine above) and returns the best offset to use
235: * when a vertical motion is made into the line.
236: */
1.3 millert 237: int
1.21 deraadt 238: getgoal(struct line *dlp)
1.3 millert 239: {
1.14 vincent 240: int c, i, col = 0;
1.24 kjell 241: char tmp[5];
242:
1.14 vincent 243:
244: for (i = 0; i < llength(dlp); i++) {
245: c = lgetc(dlp, i);
1.1 deraadt 246: if (c == '\t'
247: #ifdef NOTAB
1.3 millert 248: && !(curbp->b_flag & BFNOTAB)
1.1 deraadt 249: #endif
1.14 vincent 250: ) {
251: col |= 0x07;
252: col++;
253: } else if (ISCTRL(c) != FALSE) {
254: col += 2;
255: } else if (isprint(c))
256: col++;
257: else {
1.24 kjell 258: col += snprintf(tmp, sizeof(tmp), "\\%o", c);
1.14 vincent 259: }
260: if (col > curgoal)
1.1 deraadt 261: break;
262: }
1.14 vincent 263: return (i);
1.1 deraadt 264: }
265:
266: /*
267: * Scroll forward by a specified number
268: * of lines, or by a full page if no argument.
269: * The "2" is the window overlap (this is the default
270: * value from ITS EMACS). Because the top line in
271: * the window is zapped, we have to do a hard
272: * update and get it back.
273: */
1.3 millert 274: /* ARGSUSED */
275: int
1.12 vincent 276: forwpage(int f, int n)
1.1 deraadt 277: {
1.21 deraadt 278: struct line *lp;
1.1 deraadt 279:
280: if (!(f & FFARG)) {
1.3 millert 281: n = curwp->w_ntrows - 2; /* Default scroll. */
282: if (n <= 0) /* Forget the overlap */
283: n = 1; /* if tiny window. */
1.1 deraadt 284: } else if (n < 0)
1.18 db 285: return (backpage(f | FFRAND, -n));
1.31 lum 286:
1.1 deraadt 287: lp = curwp->w_linep;
1.31 lum 288: while (n--)
1.34 lum 289: if ((lp = lforw(lp)) == curbp->b_headp) {
1.40 ! lum 290: dobeep();
1.34 lum 291: ewprintf("End of buffer");
1.31 lum 292: return(TRUE);
1.34 lum 293: }
1.31 lum 294:
1.1 deraadt 295: curwp->w_linep = lp;
1.30 kjell 296: curwp->w_rflag |= WFFULL;
1.31 lum 297:
1.1 deraadt 298: /* if in current window, don't move dot */
1.32 lum 299: for (n = curwp->w_ntrows; n-- && lp != curbp->b_headp; lp = lforw(lp))
1.3 millert 300: if (lp == curwp->w_dotp)
1.18 db 301: return (TRUE);
1.31 lum 302:
1.27 kjell 303: /* Advance the dot the slow way, for line nos */
304: while (curwp->w_dotp != curwp->w_linep) {
305: curwp->w_dotp = lforw(curwp->w_dotp);
306: curwp->w_dotline++;
307: }
1.3 millert 308: curwp->w_doto = 0;
1.18 db 309: return (TRUE);
1.1 deraadt 310: }
311:
312: /*
313: * This command is like "forwpage",
314: * but it goes backwards. The "2", like above,
315: * is the overlap between the two windows. The
316: * value is from the ITS EMACS manual. The
317: * hard update is done because the top line in
318: * the window is zapped.
319: */
1.3 millert 320: /* ARGSUSED */
321: int
1.12 vincent 322: backpage(int f, int n)
1.1 deraadt 323: {
1.33 lum 324: struct line *lp, *lp2;
1.1 deraadt 325:
326: if (!(f & FFARG)) {
1.3 millert 327: n = curwp->w_ntrows - 2; /* Default scroll. */
328: if (n <= 0) /* Don't blow up if the */
1.35 lum 329: return (backline(f, 1));/* window is tiny. */
1.1 deraadt 330: } else if (n < 0)
1.18 db 331: return (forwpage(f | FFRAND, -n));
1.33 lum 332:
333: lp = lp2 = curwp->w_linep;
334:
1.25 kjell 335: while (n-- && lback(lp) != curbp->b_headp) {
1.1 deraadt 336: lp = lback(lp);
1.34 lum 337: }
338: if (lp == curwp->w_linep) {
1.40 ! lum 339: dobeep();
1.34 lum 340: ewprintf("Beginning of buffer");
1.23 kjell 341: }
1.1 deraadt 342: curwp->w_linep = lp;
1.30 kjell 343: curwp->w_rflag |= WFFULL;
1.33 lum 344:
1.1 deraadt 345: /* if in current window, don't move dot */
1.25 kjell 346: for (n = curwp->w_ntrows; n-- && lp != curbp->b_headp; lp = lforw(lp))
1.3 millert 347: if (lp == curwp->w_dotp)
1.18 db 348: return (TRUE);
1.33 lum 349:
350: lp2 = lforw(lp2);
351:
1.27 kjell 352: /* Move the dot the slow way, for line nos */
1.33 lum 353: while (curwp->w_dotp != lp2) {
1.36 lum 354: if (curwp->w_dotline <= curwp->w_ntrows)
355: return (TRUE);
1.27 kjell 356: curwp->w_dotp = lback(curwp->w_dotp);
357: curwp->w_dotline--;
358: }
1.1 deraadt 359: curwp->w_doto = 0;
1.18 db 360: return (TRUE);
1.1 deraadt 361: }
362:
1.3 millert 363: /*
364: * These functions are provided for compatibility with Gosling's Emacs. They
365: * are used to scroll the display up (or down) one line at a time.
1.1 deraadt 366: */
1.7 deraadt 367: int
1.12 vincent 368: forw1page(int f, int n)
1.1 deraadt 369: {
1.3 millert 370: if (!(f & FFARG)) {
371: n = 1;
1.1 deraadt 372: f = FFUNIV;
373: }
1.3 millert 374: forwpage(f | FFRAND, n);
1.18 db 375: return (TRUE);
1.1 deraadt 376: }
377:
1.7 deraadt 378: int
1.12 vincent 379: back1page(int f, int n)
1.1 deraadt 380: {
381: if (!(f & FFARG)) {
1.3 millert 382: n = 1;
1.1 deraadt 383: f = FFUNIV;
384: }
1.3 millert 385: backpage(f | FFRAND, n);
1.18 db 386: return (TRUE);
1.1 deraadt 387: }
388:
389: /*
390: * Page the other window. Check to make sure it exists, then
391: * nextwind, forwpage and restore window pointers.
392: */
1.3 millert 393: int
1.12 vincent 394: pagenext(int f, int n)
1.1 deraadt 395: {
1.21 deraadt 396: struct mgwin *wp;
1.1 deraadt 397:
398: if (wheadp->w_wndp == NULL) {
399: ewprintf("No other window");
1.18 db 400: return (FALSE);
1.1 deraadt 401: }
402: wp = curwp;
1.6 art 403: (void) nextwind(f, n);
404: (void) forwpage(f, n);
1.1 deraadt 405: curwp = wp;
406: curbp = wp->w_bufp;
1.18 db 407: return (TRUE);
1.1 deraadt 408: }
409:
410: /*
411: * Internal set mark routine, used by other functions (daveb).
412: */
1.6 art 413: void
1.12 vincent 414: isetmark(void)
1.1 deraadt 415: {
416: curwp->w_markp = curwp->w_dotp;
417: curwp->w_marko = curwp->w_doto;
1.23 kjell 418: curwp->w_markline = curwp->w_dotline;
1.1 deraadt 419: }
420:
421: /*
422: * Set the mark in the current window
423: * to the value of dot. A message is written to
424: * the echo line. (ewprintf knows about macros)
425: */
1.3 millert 426: /* ARGSUSED */
427: int
1.12 vincent 428: setmark(int f, int n)
1.1 deraadt 429: {
430: isetmark();
431: ewprintf("Mark set");
1.29 kjell 432: return (TRUE);
433: }
434:
435: /* Clear the mark, if set. */
436: /* ARGSUSED */
437: int
438: clearmark(int f, int n)
439: {
440: if (!curwp->w_markp)
441: return (FALSE);
442:
443: curwp->w_markp = NULL;
444: curwp->w_marko = 0;
445: curwp->w_markline = 0;
446:
1.18 db 447: return (TRUE);
1.1 deraadt 448: }
449:
450: /*
451: * Swap the values of "dot" and "mark" in
452: * the current window. This is pretty easy, because
453: * all of the hard work gets done by the standard routine
454: * that moves the mark about. The only possible
455: * error is "no mark".
456: */
1.3 millert 457: /* ARGSUSED */
458: int
1.12 vincent 459: swapmark(int f, int n)
1.1 deraadt 460: {
1.21 deraadt 461: struct line *odotp;
1.23 kjell 462: int odoto, odotline;
1.1 deraadt 463:
464: if (curwp->w_markp == NULL) {
465: ewprintf("No mark in this window");
1.18 db 466: return (FALSE);
1.1 deraadt 467: }
468: odotp = curwp->w_dotp;
469: odoto = curwp->w_doto;
1.23 kjell 470: odotline = curwp->w_dotline;
1.3 millert 471: curwp->w_dotp = curwp->w_markp;
472: curwp->w_doto = curwp->w_marko;
1.23 kjell 473: curwp->w_dotline = curwp->w_markline;
1.1 deraadt 474: curwp->w_markp = odotp;
475: curwp->w_marko = odoto;
1.23 kjell 476: curwp->w_markline = odotline;
1.30 kjell 477: curwp->w_rflag |= WFMOVE;
1.18 db 478: return (TRUE);
1.1 deraadt 479: }
480:
481: /*
482: * Go to a specific line, mostly for
483: * looking up errors in C programs, which give the
484: * error a line number. If an argument is present, then
485: * it is the line number, else prompt for a line number
486: * to use.
487: */
1.3 millert 488: /* ARGSUSED */
489: int
1.12 vincent 490: gotoline(int f, int n)
1.1 deraadt 491: {
1.23 kjell 492: char buf[32], *bufp;
493: const char *err;
1.1 deraadt 494:
495: if (!(f & FFARG)) {
1.20 kjell 496: if ((bufp = eread("Goto line: ", buf, sizeof(buf),
497: EFNUL | EFNEW | EFCR)) == NULL)
1.24 kjell 498: return (ABORT);
499: if (bufp[0] == '\0')
1.18 db 500: return (ABORT);
1.23 kjell 501: n = (int)strtonum(buf, INT_MIN, INT_MAX, &err);
502: if (err) {
503: ewprintf("Line number %s", err);
1.18 db 504: return (FALSE);
1.9 vincent 505: }
1.1 deraadt 506: }
1.38 jasper 507: return(setlineno(n));
508: }
509:
510: /*
511: * Set the line number and switch to it.
512: */
513: int
514: setlineno(int n)
515: {
516: struct line *clp;
517:
1.5 millert 518: if (n >= 0) {
1.23 kjell 519: if (n == 0)
520: n++;
521: curwp->w_dotline = n;
1.25 kjell 522: clp = lforw(curbp->b_headp); /* "clp" is first line */
1.1 deraadt 523: while (--n > 0) {
1.25 kjell 524: if (lforw(clp) == curbp->b_headp) {
1.23 kjell 525: curwp->w_dotline = curwp->w_bufp->b_lines;
1.3 millert 526: break;
1.23 kjell 527: }
1.1 deraadt 528: clp = lforw(clp);
529: }
530: } else {
1.23 kjell 531: curwp->w_dotline = curwp->w_bufp->b_lines + n;
1.25 kjell 532: clp = lback(curbp->b_headp); /* "clp" is last line */
1.1 deraadt 533: while (n < 0) {
1.25 kjell 534: if (lback(clp) == curbp->b_headp) {
1.23 kjell 535: curwp->w_dotline = 1;
1.3 millert 536: break;
1.23 kjell 537: }
1.1 deraadt 538: clp = lback(clp);
539: n++;
540: }
541: }
542: curwp->w_dotp = clp;
543: curwp->w_doto = 0;
1.30 kjell 544: curwp->w_rflag |= WFMOVE;
1.18 db 545: return (TRUE);
1.1 deraadt 546: }