GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/mg/basic.c Lines: 0 242 0.0 %
Date: 2017-11-07 Branches: 0 138 0.0 %

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