Annotation of src/usr.bin/mg/basic.c, Revision 1.2
1.1 deraadt 1: /*
2: * Basic cursor motion commands.
3: *
4: * The routines in this file are the basic
5: * command functions for moving the cursor around on
6: * the screen, setting mark, and swapping dot with
7: * mark. Only moves between lines, which might make the
8: * current buffer framing bad, are hard.
9: */
10: #include "def.h"
11:
12: VOID setgoal();
13:
14: /*
15: * Go to beginning of line.
16: */
17: /*ARGSUSED*/
18: gotobol(f, n)
19: {
20: curwp->w_doto = 0;
21: return (TRUE);
22: }
23:
24: /*
25: * Move cursor backwards. Do the
26: * right thing if the count is less than
27: * 0. Error if you try to move back from
28: * the beginning of the buffer.
29: */
30: /*ARGSUSED*/
31: backchar(f, n)
32: register int n;
33: {
34: register LINE *lp;
35:
36: if (n < 0) return forwchar(f, -n);
37: while (n--) {
38: if (curwp->w_doto == 0) {
39: if ((lp=lback(curwp->w_dotp)) == curbp->b_linep) {
40: if (!(f & FFRAND))
41: ewprintf("Beginning of buffer");
42: return (FALSE);
43: }
44: curwp->w_dotp = lp;
45: curwp->w_doto = llength(lp);
46: curwp->w_flag |= WFMOVE;
47: } else
48: curwp->w_doto--;
49: }
50: return TRUE;
51: }
52:
53: /*
54: * Go to end of line.
55: */
56: /*ARGSUSED*/
57: gotoeol(f, n)
58: {
59: curwp->w_doto = llength(curwp->w_dotp);
60: return (TRUE);
61: }
62:
63: /*
64: * Move cursor forwards. Do the
65: * right thing if the count is less than
66: * 0. Error if you try to move forward
67: * from the end of the buffer.
68: */
69: /*ARGSUSED*/
70: forwchar(f, n)
71: register int n;
72: {
73: if (n < 0) return backchar(f, -n);
74: while (n--) {
75: if (curwp->w_doto == llength(curwp->w_dotp)) {
76: curwp->w_dotp = lforw(curwp->w_dotp);
77: if (curwp->w_dotp == curbp->b_linep) {
78: curwp->w_dotp = lback(curwp->w_dotp);
79: if (!(f & FFRAND))
80: ewprintf("End of buffer");
81: return FALSE;
82: }
83: curwp->w_doto = 0;
84: curwp->w_flag |= WFMOVE;
85: } else
86: curwp->w_doto++;
87: }
88: return TRUE;
89: }
90:
91: /*
92: * Go to the beginning of the
93: * buffer. Setting WFHARD is conservative,
94: * but almost always the case.
95: */
96: gotobob(f, n)
97: {
98: (VOID) setmark(f, n) ;
99: curwp->w_dotp = lforw(curbp->b_linep);
100: curwp->w_doto = 0;
101: curwp->w_flag |= WFHARD;
102: return TRUE;
103: }
104:
105: /*
106: * Go to the end of the buffer.
107: * Setting WFHARD is conservative, but
108: * almost always the case.
109: */
110: gotoeob(f, n)
111: {
112: (VOID) setmark(f, n) ;
113: curwp->w_dotp = lback(curbp->b_linep);
114: curwp->w_doto = llength(curwp->w_dotp);
115: curwp->w_flag |= WFHARD;
116: return TRUE;
117: }
118:
119: /*
120: * Move forward by full lines.
121: * If the number of lines to move is less
122: * than zero, call the backward line function to
123: * actually do it. The last command controls how
124: * the goal column is set.
125: */
126: /*ARGSUSED*/
127: forwline(f, n)
128: {
129: register LINE *dlp;
130:
131: if (n < 0)
132: return backline(f|FFRAND, -n);
133: if ((lastflag&CFCPCN) == 0) /* Fix goal. */
134: setgoal();
135: thisflag |= CFCPCN;
136: if (n == 0) return TRUE;
137: dlp = curwp->w_dotp;
138: while (dlp!=curbp->b_linep && n--)
139: dlp = lforw(dlp);
140: curwp->w_flag |= WFMOVE;
141: if(dlp==curbp->b_linep) { /* ^N at end of buffer creates lines (like gnu) */
142: if(!(curbp->b_flag&BFCHG)) { /* first change */
143: curbp->b_flag |= BFCHG;
144: curwp->w_flag |= WFMODE;
145: }
146: curwp->w_doto = 0;
147: while(n-- >= 0) {
148: if((dlp = lallocx(0)) == NULL) return FALSE;
149: dlp->l_fp = curbp->b_linep;
150: dlp->l_bp = lback(dlp->l_fp);
151: dlp->l_bp->l_fp = dlp->l_fp->l_bp = dlp;
152: }
153: curwp->w_dotp = lback(curbp->b_linep);
154: } else {
155: curwp->w_dotp = dlp;
156: curwp->w_doto = getgoal(dlp);
157: }
158: return TRUE;
159: }
160:
161: /*
162: * This function is like "forwline", but
163: * goes backwards. The scheme is exactly the same.
164: * Check for arguments that are less than zero and
165: * call your alternate. Figure out the new line and
166: * call "movedot" to perform the motion.
167: */
168: /*ARGSUSED*/
169: backline(f, n)
170: {
171: register LINE *dlp;
172:
173: if (n < 0) return forwline(f|FFRAND, -n);
174: if ((lastflag&CFCPCN) == 0) /* Fix goal. */
175: setgoal();
176: thisflag |= CFCPCN;
177: dlp = curwp->w_dotp;
178: while (n-- && lback(dlp)!=curbp->b_linep)
179: dlp = lback(dlp);
180: curwp->w_dotp = dlp;
181: curwp->w_doto = getgoal(dlp);
182: curwp->w_flag |= WFMOVE;
183: return TRUE;
184: }
185:
186: /*
187: * Set the current goal column,
188: * which is saved in the external variable "curgoal",
189: * to the current cursor column. The column is never off
190: * the edge of the screen; it's more like display then
191: * show position.
192: */
193: VOID
194: setgoal() {
195:
196: curgoal = getcolpos() - 1; /* Get the position. */
197: /* we can now display past end of display, don't chop! */
198: }
199:
200: /*
201: * This routine looks at a line (pointed
202: * to by the LINE pointer "dlp") and the current
203: * vertical motion goal column (set by the "setgoal"
204: * routine above) and returns the best offset to use
205: * when a vertical motion is made into the line.
206: */
207: getgoal(dlp) register LINE *dlp; {
208: register int c;
209: register int col;
210: register int newcol;
211: register int dbo;
212:
213: col = 0;
214: dbo = 0;
215: while (dbo != llength(dlp)) {
216: c = lgetc(dlp, dbo);
217: newcol = col;
218: if (c == '\t'
219: #ifdef NOTAB
220: && !(curbp->b_flag & BFNOTAB)
221: #endif
222: )
223: newcol |= 0x07;
224: else if (ISCTRL(c) != FALSE)
225: ++newcol;
226: ++newcol;
227: if (newcol > curgoal)
228: break;
229: col = newcol;
230: ++dbo;
231: }
232: return (dbo);
233: }
234:
235: /*
236: * Scroll forward by a specified number
237: * of lines, or by a full page if no argument.
238: * The "2" is the window overlap (this is the default
239: * value from ITS EMACS). Because the top line in
240: * the window is zapped, we have to do a hard
241: * update and get it back.
242: */
243: /*ARGSUSED*/
244: forwpage(f, n)
245: register int n;
246: {
247: register LINE *lp;
248:
249: if (!(f & FFARG)) {
250: n = curwp->w_ntrows - 2; /* Default scroll. */
251: if (n <= 0) /* Forget the overlap */
252: n = 1; /* if tiny window. */
253: } else if (n < 0)
254: return backpage(f|FFRAND, -n);
255: #ifdef CVMVAS
256: else /* Convert from pages */
257: n *= curwp->w_ntrows; /* to lines. */
258: #endif
259: lp = curwp->w_linep;
260: while (n-- && lforw(lp)!=curbp->b_linep)
261: lp = lforw(lp);
262: curwp->w_linep = lp;
263: curwp->w_flag |= WFHARD;
264: /* if in current window, don't move dot */
265: for(n = curwp->w_ntrows; n-- && lp!=curbp->b_linep; lp = lforw(lp))
266: if(lp==curwp->w_dotp) return TRUE;
267: curwp->w_dotp = curwp->w_linep;
268: curwp->w_doto = 0;
269: return TRUE;
270: }
271:
272: /*
273: * This command is like "forwpage",
274: * but it goes backwards. The "2", like above,
275: * is the overlap between the two windows. The
276: * value is from the ITS EMACS manual. The
277: * hard update is done because the top line in
278: * the window is zapped.
279: */
280: /*ARGSUSED*/
281: backpage(f, n)
282: register int n;
283: {
284: register LINE *lp;
285:
286: if (!(f & FFARG)) {
287: n = curwp->w_ntrows - 2; /* Default scroll. */
288: if (n <= 0) /* Don't blow up if the */
289: n = 1; /* window is tiny. */
290: } else if (n < 0)
291: return forwpage(f|FFRAND, -n);
292: #ifdef CVMVAS
293: else /* Convert from pages */
294: n *= curwp->w_ntrows; /* to lines. */
295: #endif
296: lp = curwp->w_linep;
297: while (n-- && lback(lp)!=curbp->b_linep)
298: lp = lback(lp);
299: curwp->w_linep = lp;
300: curwp->w_flag |= WFHARD;
301: /* if in current window, don't move dot */
302: for(n = curwp->w_ntrows; n-- && lp!=curbp->b_linep; lp = lforw(lp))
303: if(lp==curwp->w_dotp) return TRUE;
304: curwp->w_dotp = curwp->w_linep;
305: curwp->w_doto = 0;
306: return TRUE;
307: }
308:
309: /* These functions are provided for compatibility with Gosling's Emacs.
310: * They are used to scroll the display up (or down) one line at a time.
311: */
312:
313: #ifdef GOSMACS
314: forw1page(f, n)
315: int f, n;
316: {
317: if (!(f & FFARG)) {
318: n = 1;
319: f = FFUNIV;
320: }
321: forwpage(f|FFRAND, n);
322: }
323:
324: back1page(f, n)
325: int f, n;
326: {
327: if (!(f & FFARG)) {
328: n = 1;
329: f = FFUNIV;
330: }
331: backpage(f|FFRAND, n);
332: }
333: #endif
334:
335: /*
336: * Page the other window. Check to make sure it exists, then
337: * nextwind, forwpage and restore window pointers.
338: */
339: pagenext(f, n)
340: {
1.2 ! millert 341: register MGWIN *wp;
1.1 deraadt 342:
343: if (wheadp->w_wndp == NULL) {
344: ewprintf("No other window");
345: return FALSE;
346: }
347: wp = curwp;
348: (VOID) nextwind(f, n);
349: (VOID) forwpage(f, n);
350: curwp = wp;
351: curbp = wp->w_bufp;
352: return TRUE;
353: }
354:
355: /*
356: * Internal set mark routine, used by other functions (daveb).
357: */
358: VOID
359: isetmark()
360: {
361: curwp->w_markp = curwp->w_dotp;
362: curwp->w_marko = curwp->w_doto;
363: }
364:
365: /*
366: * Set the mark in the current window
367: * to the value of dot. A message is written to
368: * the echo line. (ewprintf knows about macros)
369: */
370: /*ARGSUSED*/
371: setmark(f, n)
372: {
373: isetmark();
374: ewprintf("Mark set");
375: return TRUE;
376: }
377:
378: /*
379: * Swap the values of "dot" and "mark" in
380: * the current window. This is pretty easy, because
381: * all of the hard work gets done by the standard routine
382: * that moves the mark about. The only possible
383: * error is "no mark".
384: */
385: /*ARGSUSED*/
386: swapmark(f, n)
387: {
388: register LINE *odotp;
389: register int odoto;
390:
391: if (curwp->w_markp == NULL) {
392: ewprintf("No mark in this window");
393: return FALSE;
394: }
395: odotp = curwp->w_dotp;
396: odoto = curwp->w_doto;
397: curwp->w_dotp = curwp->w_markp;
398: curwp->w_doto = curwp->w_marko;
399: curwp->w_markp = odotp;
400: curwp->w_marko = odoto;
401: curwp->w_flag |= WFMOVE;
402: return TRUE;
403: }
404:
405: /*
406: * Go to a specific line, mostly for
407: * looking up errors in C programs, which give the
408: * error a line number. If an argument is present, then
409: * it is the line number, else prompt for a line number
410: * to use.
411: */
412: /*ARGSUSED*/
413: gotoline(f, n)
414: register int n;
415: {
416: register LINE *clp;
417: register int s;
418: char buf[32];
419:
420: if (!(f & FFARG)) {
421: if ((s=ereply("Goto line: ", buf, sizeof(buf))) != TRUE)
422: return s;
423: n = atoi(buf);
424: }
425:
426: if (n > 0) {
427: clp = lforw(curbp->b_linep); /* "clp" is first line */
428: while (--n > 0) {
429: if (lforw(clp) == curbp->b_linep) break;
430: clp = lforw(clp);
431: }
432: } else {
433: clp = lback(curbp->b_linep); /* clp is last line */
434: while (n < 0) {
435: if (lback(clp) == curbp->b_linep) break;
436: clp = lback(clp);
437: n++;
438: }
439: }
440: curwp->w_dotp = clp;
441: curwp->w_doto = 0;
442: curwp->w_flag |= WFMOVE;
443: return TRUE;
444: }