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