source: trunk/minix/commands/elvis/move1.c@ 21

Last change on this file since 21 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 10.0 KB
Line 
1/* move1.c */
2
3/* Author:
4 * Steve Kirkendall
5 * 14407 SW Teal Blvd. #C
6 * Beaverton, OR 97005
7 * kirkenda@cs.pdx.edu
8 */
9
10
11/* This file contains most movement functions */
12
13#include "config.h"
14#include "vi.h"
15#include "ctype.h"
16
17MARK m_updnto(m, cnt, cmd)
18 MARK m; /* movement is relative to this mark */
19 long cnt; /* a numeric argument */
20 char cmd; /* the command character */
21{
22 DEFAULT(cmd == 'G' ? nlines : 1L);
23
24 /* move up or down 'cnt' lines */
25 switch (cmd)
26 {
27 case ctrl('P'):
28 case '-':
29 case 'k':
30 m -= MARK_AT_LINE(cnt);
31 break;
32
33 case 'G':
34 if (cnt < 1L || cnt > nlines)
35 {
36 msg("Only %ld lines", nlines);
37 return MARK_UNSET;
38 }
39 m = MARK_AT_LINE(cnt);
40 break;
41
42 case '_':
43 cnt--;
44 /* fall through... */
45
46 default:
47 m += MARK_AT_LINE(cnt);
48 }
49
50 /* if that left us screwed up, then fail */
51 if (m < MARK_FIRST || markline(m) > nlines)
52 {
53 return MARK_UNSET;
54 }
55
56 return m;
57}
58
59/*ARGSUSED*/
60MARK m_right(m, cnt, key, prevkey)
61 MARK m; /* movement is relative to this mark */
62 long cnt; /* a numeric argument */
63 int key; /* movement keystroke */
64 int prevkey;/* operator keystroke, or 0 if none */
65{
66 int idx; /* index of the new cursor position */
67
68 DEFAULT(1);
69
70 /* If used with an operator, then move 1 less character, since the 'l'
71 * command includes the character that it moves onto.
72 */
73 if (prevkey != '\0')
74 {
75 cnt--;
76 }
77
78 /* move to right, if that's OK */
79 pfetch(markline(m));
80 idx = markidx(m) + cnt;
81 if (idx < plen)
82 {
83 m += cnt;
84 }
85 else
86 {
87 return MARK_UNSET;
88 }
89
90 return m;
91}
92
93/*ARGSUSED*/
94MARK m_left(m, cnt)
95 MARK m; /* movement is relative to this mark */
96 long cnt; /* a numeric argument */
97{
98 DEFAULT(1);
99
100 /* move to the left, if that's OK */
101 if (markidx(m) >= cnt)
102 {
103 m -= cnt;
104 }
105 else
106 {
107 return MARK_UNSET;
108 }
109
110 return m;
111}
112
113/*ARGSUSED*/
114MARK m_tocol(m, cnt, cmd)
115 MARK m; /* movement is relative to this mark */
116 long cnt; /* a numeric argument */
117 int cmd; /* either ctrl('X') or '|' */
118{
119 char *text; /* text of the line */
120 int col; /* column number */
121 int idx; /* index into the line */
122
123
124 /* if doing ^X, then adjust for sideways scrolling */
125 if (cmd == ctrl('X'))
126 {
127 DEFAULT(*o_columns & 0xff);
128 cnt += leftcol;
129 }
130 else
131 {
132 DEFAULT(1);
133 }
134
135 /* internally, columns are numbered 0..COLS-1, not 1..COLS */
136 cnt--;
137
138 /* if 0, that's easy */
139 if (cnt == 0)
140 {
141 m &= ~(BLKSIZE - 1);
142 return m;
143 }
144
145 /* find that column within the line */
146 pfetch(markline(m));
147 text = ptext;
148 for (col = idx = 0; col < cnt && *text; text++, idx++)
149 {
150 if (*text == '\t' && !*o_list)
151 {
152 col += *o_tabstop;
153 col -= col % *o_tabstop;
154 }
155 else if (UCHAR(*text) < ' ' || *text == '\177')
156 {
157 col += 2;
158 }
159#ifndef NO_CHARATTR
160 else if (text[0] == '\\' && text[1] == 'f' && text[2] && *o_charattr)
161 {
162 text += 2; /* plus one more as part of for loop */
163 }
164#endif
165 else
166 {
167 col++;
168 }
169 }
170 if (!*text)
171 {
172 /* the desired column was past the end of the line, so
173 * act like the user pressed "$" instead.
174 */
175 return m | (BLKSIZE - 1);
176 }
177 else
178 {
179 m = (m & ~(BLKSIZE - 1)) + idx;
180 }
181 return m;
182}
183
184/*ARGSUSED*/
185MARK m_front(m, cnt)
186 MARK m; /* movement is relative to this mark */
187 long cnt; /* a numeric argument (ignored) */
188{
189 char *scan;
190
191 /* move to the first non-whitespace character */
192 pfetch(markline(m));
193 scan = ptext;
194 m &= ~(BLKSIZE - 1);
195 while (*scan == ' ' || *scan == '\t')
196 {
197 scan++;
198 m++;
199 }
200
201 return m;
202}
203
204/*ARGSUSED*/
205MARK m_rear(m, cnt)
206 MARK m; /* movement is relative to this mark */
207 long cnt; /* a numeric argument (ignored) */
208{
209 /* Try to move *EXTREMELY* far to the right. It is fervently hoped
210 * that other code will convert this to a more reasonable MARK before
211 * anything tries to actually use it. (See adjmove() in vi.c)
212 */
213 return m | (BLKSIZE - 1);
214}
215
216#ifndef NO_SENTENCE
217static int isperiod(ptr)
218 char *ptr; /* pointer to possible sentence-ender */
219{
220 /* if not '.', '?', or '!', then it isn't a sentence ender */
221 if (*ptr != '.' && *ptr != '?' && *ptr != '!')
222 {
223 return FALSE;
224 }
225
226 /* skip any intervening ')', ']', or '"' characters */
227 do
228 {
229 ptr++;
230 } while (*ptr == ')' || *ptr == ']' || *ptr == '"');
231
232 /* do we have two spaces or EOL? */
233 if (!*ptr || ptr[0] == ' ' && ptr[1] == ' ')
234 {
235 return TRUE;
236 }
237 return FALSE;
238}
239
240/*ARGSUSED*/
241MARK m_sentence(m, cnt, cmd)
242 MARK m; /* movement is relative to this mark */
243 long cnt; /* a numeric argument */
244 int cmd; /* either '(' or ')' */
245{
246 REG char *text;
247 REG long l;
248
249 DEFAULT(1);
250
251 /* If '(' command, then move back one word, so that if we hit '(' at
252 * the start of a sentence we don't simply stop at the end of the
253 * previous sentence and bounce back to the start of this one again.
254 */
255 if (cmd == '(')
256 {
257 m = m_bword(m, 1L, 'b');
258 if (!m)
259 {
260 return m;
261 }
262 }
263
264 /* get the current line */
265 l = markline(m);
266 pfetch(l);
267 text = ptext + markidx(m);
268
269 /* for each requested sentence... */
270 while (cnt-- > 0)
271 {
272 /* search forward for one of [.?!] followed by spaces or EOL */
273 do
274 {
275 if (cmd == ')')
276 {
277 /* move forward, wrap at end of line */
278 if (!text[0])
279 {
280 if (l >= nlines)
281 {
282 return MARK_UNSET;
283 }
284 l++;
285 pfetch(l);
286 text = ptext;
287 }
288 else
289 {
290 text++;
291 }
292 }
293 else
294 {
295 /* move backward, wrap at beginning of line */
296 if (text == ptext)
297 {
298 do
299 {
300 if (l <= 1)
301 {
302 return MARK_FIRST;
303 }
304 l--;
305 pfetch(l);
306 } while (!*ptext);
307 text = ptext + plen - 1;
308 }
309 else
310 {
311 text--;
312 }
313 }
314 } while (!isperiod(text));
315 }
316
317 /* construct a mark for this location */
318 m = buildmark(text);
319
320 /* move forward to the first word of the next sentence */
321 m = m_fword(m, 1L, 'w', '\0');
322
323 return m;
324}
325#endif
326
327MARK m_paragraph(m, cnt, cmd)
328 MARK m; /* movement is relative to this mark */
329 long cnt; /* a numeric argument */
330 int cmd; /* either '{' or '}' */
331{
332 char *text; /* text of the current line */
333 char *pscn; /* used to scan thru value of "paragraphs" option */
334 long l, ol; /* current line number, original line number */
335 int dir; /* -1 if we're moving up, or 1 if down */
336 char col0; /* character to expect in column 0 */
337#ifndef NO_SENTENCE
338# define SENTENCE(x) (x)
339 char *list; /* either o_sections or o_paragraph */
340#else
341# define SENTENCE(x)
342#endif
343
344 DEFAULT(1);
345
346 /* set the direction, based on the command */
347 switch (cmd)
348 {
349 case '{':
350 dir = -1;
351 col0 = '\0';
352 SENTENCE(list = o_paragraphs);
353 break;
354
355 case '}':
356 dir = 1;
357 col0 = '\0';
358 SENTENCE(list = o_paragraphs);
359 break;
360
361 case '[':
362 if (getkey(0) != '[')
363 {
364 return MARK_UNSET;
365 }
366 dir = -1;
367 col0 = '{';
368 SENTENCE(list = o_sections);
369 break;
370
371 case ']':
372 if (getkey(0) != ']')
373 {
374 return MARK_UNSET;
375 }
376 dir = 1;
377 col0 = '{';
378 SENTENCE(list = o_sections);
379 break;
380 }
381 ol = l = markline(m);
382
383 /* for each paragraph that we want to travel through... */
384 while (l > 0 && l <= nlines && cnt-- > 0)
385 {
386 /* skip blank lines between paragraphs */
387 while (l > 0 && l <= nlines && col0 == *(text = fetchline(l)))
388 {
389 l += dir;
390 }
391
392 /* skip non-blank lines that aren't paragraph separators
393 */
394 do
395 {
396#ifndef NO_SENTENCE
397 if (*text == '.' && l != ol)
398 {
399 for (pscn = list; pscn[0] && pscn[1]; pscn += 2)
400 {
401 if (pscn[0] == text[1] && pscn[1] == text[2])
402 {
403 pscn = (char *)0;
404 goto BreakBreak;
405 }
406 }
407 }
408#endif
409 l += dir;
410 } while (l > 0 && l <= nlines && col0 != *(text = fetchline(l)));
411BreakBreak: ;
412 }
413
414 if (l > nlines)
415 {
416 m = MARK_LAST;
417 }
418 else if (l <= 0)
419 {
420 m = MARK_FIRST;
421 }
422 else
423 {
424 m = MARK_AT_LINE(l);
425 }
426 return m;
427}
428
429
430/*ARGSUSED*/
431MARK m_match(m, cnt)
432 MARK m; /* movement is relative to this mark */
433 long cnt; /* a numeric argument (normally 0) */
434{
435 long l;
436 REG char *text;
437 REG char match;
438 REG char nest;
439 REG int count;
440
441#ifndef NO_EXTENSIONS
442 /* if we're given a number, then treat it as a percentage of the file */
443 if (cnt > 0)
444 {
445 /* make sure it is a reasonable number */
446 if (cnt > 100)
447 {
448 msg("can only be from 1%% to 100%%");
449 return MARK_UNSET;
450 }
451
452 /* return the appropriate line number */
453 l = (nlines - 1L) * cnt / 100L + 1L;
454 return MARK_AT_LINE(l);
455 }
456#endif /* undef NO_EXTENSIONS */
457
458 /* get the current line */
459 l = markline(m);
460 pfetch(l);
461 text = ptext + markidx(m);
462
463 /* search forward within line for one of "[](){}" */
464 for (match = '\0'; !match && *text; text++)
465 {
466 /* tricky way to recognize 'em in ASCII */
467 nest = *text;
468 if ((nest & 0xdf) == ']' || (nest & 0xdf) == '[')
469 {
470 match = nest ^ ('[' ^ ']');
471 }
472 else if ((nest & 0xfe) == '(')
473 {
474 match = nest ^ ('(' ^ ')');
475 }
476 else
477 {
478 match = 0;
479 }
480 }
481 if (!match)
482 {
483 return MARK_UNSET;
484 }
485 text--;
486
487 /* search forward or backward for match */
488 if (match == '(' || match == '[' || match == '{')
489 {
490 /* search backward */
491 for (count = 1; count > 0; )
492 {
493 /* wrap at beginning of line */
494 if (text == ptext)
495 {
496 do
497 {
498 if (l <= 1L)
499 {
500 return MARK_UNSET;
501 }
502 l--;
503 pfetch(l);
504 } while (!*ptext);
505 text = ptext + plen - 1;
506 }
507 else
508 {
509 text--;
510 }
511
512 /* check the char */
513 if (*text == match)
514 count--;
515 else if (*text == nest)
516 count++;
517 }
518 }
519 else
520 {
521 /* search forward */
522 for (count = 1; count > 0; )
523 {
524 /* wrap at end of line */
525 if (!*text)
526 {
527 if (l >= nlines)
528 {
529 return MARK_UNSET;
530 }
531 l++;
532 pfetch(l);
533 text = ptext;
534 }
535 else
536 {
537 text++;
538 }
539
540 /* check the char */
541 if (*text == match)
542 count--;
543 else if (*text == nest)
544 count++;
545 }
546 }
547
548 /* construct a mark for this place */
549 m = buildmark(text);
550 return m;
551}
552
553/*ARGSUSED*/
554MARK m_tomark(m, cnt, key)
555 MARK m; /* movement is relative to this mark */
556 long cnt; /* (ignored) */
557 int key; /* keystroke - the mark to move to */
558{
559 /* mark '' is a special case */
560 if (key == '\'' || key == '`')
561 {
562 if (mark[26] == MARK_UNSET)
563 {
564 return MARK_FIRST;
565 }
566 else
567 {
568 return mark[26];
569 }
570 }
571
572 /* if not a valid mark number, don't move */
573 if (key < 'a' || key > 'z')
574 {
575 return MARK_UNSET;
576 }
577
578 /* return the selected mark -- may be MARK_UNSET */
579 if (!mark[key - 'a'])
580 {
581 msg("mark '%c is unset", key);
582 }
583 return mark[key - 'a'];
584}
585
Note: See TracBrowser for help on using the repository browser.