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