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