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