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