1 /*
2 * Basic cursor motion commands.
3 * The routines in this file are the basic
4 * command functions for moving the cursor around on
5 * the screen, setting mark, and swapping dot with
6 * mark. Only moves between lines, which might make the
7 * current buffer framing bad, are hard.
8 */
9
10 #include "def.h"
11
12 bool move_ptr ();
13 bool forwchar ();
14 bool wind_on_dot ();
15 bool backline ();
16
17 extern char MSG_mark_set[];
18 extern char MSG_no_mark[];
19 extern char MSG_go_b_n[];
20 extern char MSG_bad_num[];
21 #if RUNCHK
22 extern char ERR_bas_1[];
23 #endif
24 extern char MSG_lX[];
25 extern char MSG_lO[];
26 extern char MSG_lD[];
27
28
29 extern bool rplc_mode;
30
31 /* pvr
32 * Move cursor backwards. Do the
33 * right thing if the count is less than
34 * 0. Error if you try to move back from
35 * the beginning of the buffer.
36 */
37 bool
backchar(f,n,k)38 backchar (f, n, k)
39 register int f, n, k;
40 {
41 if (n < 0)
42 return (forwchar (f, -n, KRANDOM));
43
44 while (n--)
45 {
46 if (curwp->w_unit_offset == 0)
47 {
48 if (!move_ptr (curwp, -(long) R_B_PER_U (curwp),
49 TRUE, TRUE, TRUE))
50 return (FALSE);
51
52 /* step to previous unit */
53 curwp->w_unit_offset = R_CHR_PER_U (curwp) - 1;
54
55 /* if before first line in window then move window */
56 wind_on_dot (curwp);
57 }
58 else
59 curwp->w_unit_offset--;
60 }
61 curwp->w_flag |= WFMODE; /* update mode line */
62 return (TRUE);
63 }
64
65 /* pvr
66 * Move cursor forwards. Do the
67 * right thing if the count is less than
68 * 0. Error if you try to move forward
69 * from the end of the buffer.
70 */
71 bool
forwchar(f,n,k)72 forwchar (f, n, k)
73 register int f, n, k;
74 {
75 if (n < 0)
76 return (backchar (f, -n, KRANDOM));
77
78 curwp->w_flag |= WFMODE; /* update mode line */
79 while (n--)
80 {
81 if (curwp->w_unit_offset >= (R_CHR_PER_U (curwp) - 1))
82 {
83 /* move to the mext unit */
84 curwp->w_unit_offset = 0;
85
86 if (!move_ptr (curwp, (long) R_B_PER_U (curwp),
87 TRUE, TRUE, TRUE))
88 {
89 /* I am at the the end of the buffer */
90 return (FALSE);
91 }
92
93 /* if after the last line in window then move window */
94 wind_on_dot (curwp);
95 }
96 else if /* if at last byte of buffer then do not step */
97 (DOT_POS (curwp) < BUF_SIZE (curwp))
98 curwp->w_unit_offset++; /* step within unit */
99 }
100 return (TRUE);
101 }
102
103 /* pvr
104 * This function moves the specified pointer by the ammount specified
105 * in 'len'. Move the dot pointer is 'dot' is true, else move
106 * the window pointer. Do the fix up if 'fix' is TRUE.
107 * This is a relative move if 'rel' is TRUE, else it is an
108 * absolute move.
109 */
110
111 bool
move_ptr(wp,len,dot,fix,rel)112 move_ptr (wp, len, dot, fix, rel)
113 WINDOW *wp;
114 long len;
115 bool dot, fix, rel;
116 {
117 A32 cur_pos, dest_pos, fix_val, last_pos;
118 long rel_pos;
119 A32 last_fixed_pos, align;
120 LINE **line;
121 int *l_off;
122 char shift;
123 bool no_limit;
124
125 no_limit = TRUE;
126 if (dot)
127 { /* move dot position */
128 l_off = (int *) &wp->w_doto;
129 line = &wp->w_dotp;
130 align = R_SIZE (wp); /* bytes -1 in a unit */
131 }
132 else
133 { /* move window position */
134 l_off = (int *) &wp->w_loff;
135 line = &wp->w_linep;
136 align = R_ALIGN (wp) - 1; /* interval of bytes to align window */
137 }
138
139 /* get the current position in the buffer */
140 cur_pos = (*line)->l_file_offset + *l_off;
141
142 if (rel)
143 {
144 rel_pos = len;
145 dest_pos = len + cur_pos; /* destination position */
146 }
147 else
148 {
149 rel_pos = len - cur_pos;/* relative move amount */
150 dest_pos = len; /* destination position */
151 }
152 if (fix)
153 {
154 shift = wp->w_disp_shift;
155
156 /* limit at begining */
157 if ((long) dest_pos < (long) shift)
158 {
159 rel_pos = shift - cur_pos;
160 no_limit = FALSE;
161 }
162 else
163 {
164 /* calculate fixed up destination position */
165 fix_val = dest_pos &= ~align;
166 fix_val += shift;
167
168 /* calculate the last position in the buffer */
169 last_pos = BUF_SIZE (wp);
170 if (last_pos < (last_fixed_pos = (last_pos & ~align) + shift))
171 last_pos = last_fixed_pos - align - 1;
172
173 /* if we are going to limit at the end of the buffer */
174 if (last_pos < fix_val)
175 {
176 fix_val = last_pos;
177 no_limit = FALSE;
178 }
179 rel_pos = fix_val - cur_pos;
180 }
181 }
182 while (TRUE)
183 {
184 if (rel_pos < 0) /* move backward through buffer */
185 {
186 /* current line? */
187 if (*l_off + rel_pos >= 0)
188 {
189 *l_off += (short) rel_pos;
190 return (no_limit);
191 }
192 /* are we at the first line */
193 if ((*line)->l_bp->l_size != 0)
194 { /* no, so step back */
195 rel_pos += *l_off;
196 (*line) = (*line)->l_bp; /* move back one line */
197 *l_off = (*line)->l_used;
198 }
199 else
200 { /* yes, limit at the begining */
201 *l_off = 0;
202 return (FALSE);
203 }
204 }
205 else
206 /* move forward through buffer */
207 {
208 /* is in current line? */
209 if (((A32) (*l_off) + rel_pos) < ((A32) ((*line)->l_used)))
210 {
211 *l_off += (short) rel_pos;
212 return (no_limit);
213 }
214 if ((*line)->l_fp->l_size != 0)
215 {
216 rel_pos -= (*line)->l_used - *l_off;
217 *l_off = 0;
218 (*line) = (*line)->l_fp; /* move forward one line */
219 }
220 else
221 {
222 *l_off = (*line)->l_used; /* at last line so limit it */
223 return (FALSE);
224 }
225 }
226 }
227 }
228
229 /* pvr
230 * Move the window so that the dot is within it's
231 * area. Return TRUE if window was moved.
232 */
233
234 bool
wind_on_dot(wp)235 wind_on_dot (wp)
236
237 WINDOW *wp;
238 {
239 long diff, incr;
240 A32 d_offs, w_start, bytes, align;
241
242 /* number of bytes in a row */
243 bytes = R_BYTES (wp);
244 /* number of bytes to align on */
245 align = R_ALIGN (wp);
246 /* offset of window from start of the buffer */
247 w_start = WIND_POS (wp);
248 /* offset of dot from start of the buffer */
249 d_offs = DOT_POS (wp);
250 /* calculate the amount to move that is 1/3 of the window */
251 incr = bytes * wp->w_ntrows / 3;
252 /* if dot is before first line in window */
253 if ((diff = (d_offs - w_start)) < 0) /* diff used later */
254 {
255 move_ptr (wp, diff - incr, FALSE, TRUE, TRUE);
256 wp->w_flag |= WFHARD;
257 return (TRUE);
258 }
259 /* if dot is after the last line in window */
260 if (0 < (diff -= (wp->w_ntrows * bytes - 1)))
261 {
262 if (align != 1)
263 diff = (diff & ~(align - 1)) + align;
264 move_ptr (wp, diff + incr, FALSE, TRUE, TRUE);
265 wp->w_flag |= WFHARD;
266 return (TRUE);
267 }
268 /* is window aligned? */
269 if (w_start != ((w_start & ~(align - 1)) + wp->w_disp_shift))
270 { /* if no then move into alignment */
271 move_ptr (wp, 0L, FALSE, TRUE, TRUE);
272 wp->w_flag |= WFHARD;
273 return (TRUE);
274 }
275 return (FALSE);
276 }
277
278 /* pvr
279 * Go to the beginning of the
280 * buffer. Setting WFHARD is conservative,
281 * but almost always the case.
282 */
283 bool
gotobob()284 gotobob ()
285 {
286 move_ptr (curwp, 0L, TRUE, TRUE, FALSE); /* move dot */
287 move_ptr (curwp, 0L, FALSE, TRUE, FALSE); /* move window */
288 curwp->w_unit_offset = 0;
289 curwp->w_flag |= WFHARD;
290 return (TRUE);
291 }
292
293 /* pvr
294 * Go to the end of the buffer.
295 * Setting WFHARD is conservative, but
296 * almost always the case.
297 * Dot is one byte past the end of the buffer.
298 */
299 bool
gotoeob()300 gotoeob ()
301 {
302 move_ptr (curwp, BUF_SIZE (curwp), TRUE, TRUE, FALSE); /* move dot */
303 curwp->w_unit_offset = 0;
304 wind_on_dot (curwp);
305 return (TRUE);
306 }
307
308 /* pvr
309 * Move forward by full lines.
310 * If the number of lines to move is less
311 * than zero, call the backward line function to
312 * actually do it. The last command controls how
313 * the goal column is set.
314 */
315 bool
forwline(f,n,k)316 forwline (f, n, k)
317 int f, n, k;
318 {
319 if (n < 0)
320 return (backline (f, -n, KRANDOM));
321
322 if (rplc_mode)
323 {
324 next_pat ();
325 }
326 else
327 {
328 /* move dot */
329 if (!move_ptr (curwp, (long) R_BYTES (curwp) * n,
330 TRUE, TRUE, TRUE))
331 curwp->w_unit_offset = 0;
332 wind_on_dot (curwp);
333 curwp->w_flag |= WFMODE;/* update mode line */
334 }
335 return (TRUE);
336 }
337
338 /* pvr
339 * This function is like "forwline", but
340 * goes backwards. The scheme is exactly the same.
341 * Check for arguments that are less than zero and
342 * call your alternate. Figure out the new line and
343 * call "movedot" to perform the motion.
344 */
345 bool
backline(f,n,k)346 backline (f, n, k)
347 int f, n, k;
348 {
349 if (n < 0)
350 return (forwline (f, -n, KRANDOM));
351
352 if (rplc_mode)
353 {
354 next_pat ();
355 }
356 else
357 {
358 if (!move_ptr (curwp, -((long) (R_BYTES (curwp) * n)),
359 TRUE, TRUE, TRUE))
360 curwp->w_unit_offset = 0;
361
362 /* is dot before the top of window? */
363 wind_on_dot (curwp);
364 curwp->w_flag |= WFMODE;/* update mode line */
365 }
366 return (TRUE);
367 }
368
369 /* pvr
370 * Scroll forward by a specified number
371 * of lines, or by a full page if no argument.
372 * (KRW) Added cursor (dot) weighting to force cursor
373 * to same position on new page.
374 */
375 bool
forwpage(f,n,k)376 forwpage (f, n, k)
377 int f, n, k;
378 {
379 long mov_lines;
380
381 if (rplc_mode)
382 next_pat ();
383 else
384 {
385 if (curwp->w_ntrows <= 2)
386 mov_lines = 2;
387 else
388 mov_lines = curwp->w_ntrows - 2;
389
390 /* check if last line is already displayed */
391 if (WIND_POS (curwp) + (R_BYTES (curwp) * curwp->w_ntrows) <
392 curwp->w_bufp->b_linep->l_bp->l_file_offset +
393 curwp->w_bufp->b_linep->l_bp->l_used)
394 {
395 move_ptr (curwp, (long) (R_BYTES (curwp) * mov_lines),
396 FALSE, TRUE, TRUE);
397 }
398 /* move dot by same amount */
399 if (!move_ptr (curwp, (long) (R_BYTES (curwp) * mov_lines),
400 TRUE, TRUE, TRUE))
401 curwp->w_unit_offset = 0;
402
403 curwp->w_flag |= WFHARD;
404 }
405 return (TRUE);
406 }
407
408 /* pvr
409 * This command is like "forwpage",
410 * but it goes backwards.
411 */
412 bool
backpage(f,n,k)413 backpage (f, n, k)
414 int f, n, k;
415 {
416 long mov_lines;
417
418 if (rplc_mode)
419 next_pat ();
420 else
421 {
422 if (curwp->w_ntrows <= 2)
423 mov_lines = 2;
424 else
425 mov_lines = curwp->w_ntrows - 2;
426
427 /* move window */
428 move_ptr (curwp, -(long) (R_BYTES (curwp) * mov_lines),
429 FALSE, TRUE, TRUE);
430 /* move dot by same amount */
431 if (!move_ptr (curwp, -(long) (R_BYTES (curwp) * mov_lines),
432 TRUE, TRUE, TRUE))
433 curwp->w_unit_offset = 0;
434
435 curwp->w_flag |= WFHARD;
436 }
437 return (TRUE);
438 }
439
440 /*
441 * Set the mark in the current window
442 * to the value of dot. A message is written to
443 * the echo line unless we are running in a keyboard
444 * macro, when it would be silly.
445 */
446 bool
setmark()447 setmark ()
448 {
449
450 if (curbp == blistp) /* jam - hack to do goto/kill */
451 pickone ();
452 else
453 {
454 curwp->w_markp = curwp->w_dotp;
455 curwp->w_marko = curwp->w_doto;
456 if (kbdmop == NULL)
457 {
458 writ_echo (MSG_mark_set);
459 }
460 }
461 return (TRUE);
462 }
463
464 /* pvr
465 * Swap the values of "dot" and "mark" in
466 * the current window. This is pretty easy, because
467 * all of the hard work gets done by the standard routine
468 * that moves the mark about. The only possible
469 * error is "no mark".
470 */
471 bool
swapmark()472 swapmark ()
473 {
474 register short odoto;
475 register LINE *odotp;
476
477 if (curwp->w_markp == NULL)
478 {
479 writ_echo (MSG_no_mark);
480 return (FALSE);
481 }
482
483 odotp = curwp->w_dotp;
484 curwp->w_dotp = curwp->w_markp;
485 curwp->w_markp = odotp;
486 odoto = curwp->w_doto;
487 curwp->w_doto = curwp->w_marko;
488 curwp->w_marko = odoto;
489 wind_on_dot (curwp);
490 curwp->w_flag |= WFMODE; /* update mode line */
491 return (TRUE);
492 }
493
494 /* pvr
495 * Go to a specific byte position in buffer.
496 * If an argument is present, then
497 * it is the byte number, else prompt for a byte number
498 * to use.
499 */
500 bool
gotoline(f,n,k)501 gotoline (f, n, k)
502 int f, n, k;
503 {
504 A32 index;
505 register int s;
506 char buf[32];
507
508 if (f == FALSE)
509 {
510
511 if ((s = ereply (MSG_go_b_n, buf, sizeof (buf), 0) != TRUE))
512 return (s);
513 switch (R_TYPE (curwp))
514 {
515 case TEXT:
516 case ASCII:
517 case EBCDIC:
518 case BINARY:
519 case HEX:
520 sscanf (buf, MSG_lX, &index);
521 break;
522 case OCTAL:
523 sscanf (buf, MSG_lO, &index);
524 break;
525 case DECIMAL:
526 #if FLOAT_DISP
527 case FLOAT:
528 #endif
529 sscanf (buf, MSG_lD, &index);
530 break;
531 #if RUNCHK
532 default:
533 writ_echo (ERR_bas_1);
534 break;
535 #endif
536 }
537 }
538
539 if (n <= 0)
540 {
541 writ_echo (MSG_bad_num);
542 return (FALSE);
543 }
544
545 move_ptr (curwp, index, TRUE, TRUE, FALSE);
546 curwp->w_unit_offset = 0;
547
548 curwp->w_flag |= WFMODE; /* update mode line */
549
550 wind_on_dot (curwp);
551 return (TRUE);
552 }
553