chared.c revision 1.7 1 /* $NetBSD: chared.c,v 1.7 1999/07/02 15:21:23 simonb Exp $ */
2
3 /*-
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Christos Zoulas of Cornell University.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 #if !defined(lint) && !defined(SCCSID)
41 #if 0
42 static char sccsid[] = "@(#)chared.c 8.1 (Berkeley) 6/4/93";
43 #else
44 __RCSID("$NetBSD: chared.c,v 1.7 1999/07/02 15:21:23 simonb Exp $");
45 #endif
46 #endif /* not lint && not SCCSID */
47
48 /*
49 * chared.c: Character editor utilities
50 */
51 #include "sys.h"
52
53 #include <stdlib.h>
54 #include "el.h"
55
56 /* cv_undo():
57 * Handle state for the vi undo command
58 */
59 protected void
60 cv_undo(el, action, size, ptr)
61 EditLine *el;
62 int action;
63 size_t size;
64 char *ptr;
65 {
66 c_undo_t *vu = &el->el_chared.c_undo;
67 vu->action = action;
68 vu->ptr = ptr;
69 vu->isize = size;
70 (void) memcpy(vu->buf, vu->ptr, size);
71 #ifdef DEBUG_UNDO
72 (void) fprintf(el->el_errfile, "Undo buffer \"%s\" size = +%d -%d\n",
73 vu->ptr, vu->isize, vu->dsize);
74 #endif
75 }
76
77
78 /* c_insert():
79 * Insert num characters
80 */
81 protected void
82 c_insert(el, num)
83 EditLine *el;
84 int num;
85 {
86 char *cp;
87
88 if (el->el_line.lastchar + num >= el->el_line.limit)
89 return; /* can't go past end of buffer */
90
91 if (el->el_line.cursor < el->el_line.lastchar) {
92 /* if I must move chars */
93 for (cp = el->el_line.lastchar; cp >= el->el_line.cursor; cp--)
94 cp[num] = *cp;
95 }
96 el->el_line.lastchar += num;
97 } /* end c_insert */
98
99
100 /* c_delafter():
101 * Delete num characters after the cursor
102 */
103 protected void
104 c_delafter(el, num)
105 EditLine *el;
106 int num;
107 {
108
109 if (el->el_line.cursor + num > el->el_line.lastchar)
110 num = el->el_line.lastchar - el->el_line.cursor;
111
112 if (num > 0) {
113 char *cp;
114
115 if (el->el_map.current != el->el_map.emacs)
116 cv_undo(el, INSERT, (size_t)num, el->el_line.cursor);
117
118 for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
119 *cp = cp[num];
120
121 el->el_line.lastchar -= num;
122 }
123 }
124
125
126 /* c_delbefore():
127 * Delete num characters before the cursor
128 */
129 protected void
130 c_delbefore(el, num)
131 EditLine *el;
132 int num;
133 {
134
135 if (el->el_line.cursor - num < el->el_line.buffer)
136 num = el->el_line.cursor - el->el_line.buffer;
137
138 if (num > 0) {
139 char *cp;
140
141 if (el->el_map.current != el->el_map.emacs)
142 cv_undo(el, INSERT, (size_t)num, el->el_line.cursor - num);
143
144 for (cp = el->el_line.cursor - num; cp <= el->el_line.lastchar; cp++)
145 *cp = cp[num];
146
147 el->el_line.lastchar -= num;
148 }
149 }
150
151
152 /* ce__isword():
153 * Return if p is part of a word according to emacs
154 */
155 protected int
156 ce__isword(p)
157 int p;
158 {
159 return isalpha(p) || isdigit(p) || strchr("*?_-.[]~=", p) != NULL;
160 }
161
162
163 /* cv__isword():
164 * Return if p is part of a word according to vi
165 */
166 protected int
167 cv__isword(p)
168 int p;
169 {
170 return !isspace(p);
171 }
172
173
174 /* c__prev_word():
175 * Find the previous word
176 */
177 protected char *
178 c__prev_word(p, low, n, wtest)
179 char *p, *low;
180 int n;
181 int (*wtest) __P((int));
182 {
183 p--;
184
185 while (n--) {
186 while ((p >= low) && !(*wtest)((unsigned char) *p))
187 p--;
188 while ((p >= low) && (*wtest)((unsigned char) *p))
189 p--;
190 }
191
192 /* cp now points to one character before the word */
193 p++;
194 if (p < low)
195 p = low;
196 /* cp now points where we want it */
197 return p;
198 }
199
200
201 /* c__next_word():
202 * Find the next word
203 */
204 protected char *
205 c__next_word(p, high, n, wtest)
206 char *p, *high;
207 int n;
208 int (*wtest) __P((int));
209 {
210 while (n--) {
211 while ((p < high) && !(*wtest)((unsigned char) *p))
212 p++;
213 while ((p < high) && (*wtest)((unsigned char) *p))
214 p++;
215 }
216 if (p > high)
217 p = high;
218 /* p now points where we want it */
219 return p;
220 }
221
222 /* cv_next_word():
223 * Find the next word vi style
224 */
225 protected char *
226 cv_next_word(el, p, high, n, wtest)
227 EditLine *el;
228 char *p, *high;
229 int n;
230 int (*wtest) __P((int));
231 {
232 int test;
233
234 while (n--) {
235 test = (*wtest)((unsigned char) *p);
236 while ((p < high) && (*wtest)((unsigned char) *p) == test)
237 p++;
238 /*
239 * vi historically deletes with cw only the word preserving the
240 * trailing whitespace! This is not what 'w' does..
241 */
242 if (el->el_chared.c_vcmd.action != (DELETE|INSERT))
243 while ((p < high) && isspace((unsigned char) *p))
244 p++;
245 }
246
247 /* p now points where we want it */
248 if (p > high)
249 return high;
250 else
251 return p;
252 }
253
254
255 /* cv_prev_word():
256 * Find the previous word vi style
257 */
258 protected char *
259 cv_prev_word(el, p, low, n, wtest)
260 EditLine *el;
261 char *p, *low;
262 int n;
263 int (*wtest) __P((int));
264 {
265 int test;
266
267 while (n--) {
268 p--;
269 /*
270 * vi historically deletes with cb only the word preserving the
271 * leading whitespace! This is not what 'b' does..
272 */
273 if (el->el_chared.c_vcmd.action != (DELETE|INSERT))
274 while ((p > low) && isspace((unsigned char) *p))
275 p--;
276 test = (*wtest)((unsigned char) *p);
277 while ((p >= low) && (*wtest)((unsigned char) *p) == test)
278 p--;
279 p++;
280 while (isspace((unsigned char) *p))
281 p++;
282 }
283
284 /* p now points where we want it */
285 if (p < low)
286 return low;
287 else
288 return p;
289 }
290
291
292 #ifdef notdef
293 /* c__number():
294 * Ignore character p points to, return number appearing after that.
295 * A '$' by itself means a big number; "$-" is for negative; '^' means 1.
296 * Return p pointing to last char used.
297 */
298 protected char *
299 c__number(p, num, dval)
300 char *p; /* character position */
301 int *num; /* Return value */
302 int dval; /* dval is the number to subtract from like $-3 */
303 {
304 int i;
305 int sign = 1;
306
307 if (*++p == '^') {
308 *num = 1;
309 return p;
310 }
311 if (*p == '$') {
312 if (*++p != '-') {
313 *num = 0x7fffffff; /* Handle $ */
314 return --p;
315 }
316 sign = -1; /* Handle $- */
317 ++p;
318 }
319 for (i = 0; isdigit((unsigned char) *p); i = 10 * i + *p++ - '0')
320 continue;
321 *num = (sign < 0 ? dval - i : i);
322 return --p;
323 }
324 #endif
325
326 /* cv_delfini():
327 * Finish vi delete action
328 */
329 protected void
330 cv_delfini(el)
331 EditLine *el;
332 {
333 int size;
334 int oaction;
335
336 if (el->el_chared.c_vcmd.action & INSERT)
337 el->el_map.current = el->el_map.key;
338
339 oaction = el->el_chared.c_vcmd.action;
340 el->el_chared.c_vcmd.action = NOP;
341
342 if (el->el_chared.c_vcmd.pos == 0)
343 return;
344
345
346 if (el->el_line.cursor > el->el_chared.c_vcmd.pos) {
347 size = (int) (el->el_line.cursor - el->el_chared.c_vcmd.pos);
348 c_delbefore(el, size);
349 el->el_line.cursor = el->el_chared.c_vcmd.pos;
350 re_refresh_cursor(el);
351 }
352 else if (el->el_line.cursor < el->el_chared.c_vcmd.pos) {
353 size = (int)(el->el_chared.c_vcmd.pos - el->el_line.cursor);
354 c_delafter(el, size);
355 }
356 else {
357 size = 1;
358 c_delafter(el, size);
359 }
360 switch (oaction) {
361 case DELETE|INSERT:
362 el->el_chared.c_undo.action = DELETE|INSERT;
363 break;
364 case DELETE:
365 el->el_chared.c_undo.action = INSERT;
366 break;
367 case NOP:
368 case INSERT:
369 default:
370 abort();
371 break;
372 }
373
374
375 el->el_chared.c_undo.ptr = el->el_line.cursor;
376 el->el_chared.c_undo.dsize = size;
377 }
378
379
380 #ifdef notdef
381 /* ce__endword():
382 * Go to the end of this word according to emacs
383 */
384 protected char *
385 ce__endword(p, high, n)
386 char *p, *high;
387 int n;
388 {
389 p++;
390
391 while (n--) {
392 while ((p < high) && isspace((unsigned char) *p))
393 p++;
394 while ((p < high) && !isspace((unsigned char) *p))
395 p++;
396 }
397
398 p--;
399 return p;
400 }
401 #endif
402
403
404 /* cv__endword():
405 * Go to the end of this word according to vi
406 */
407 protected char *
408 cv__endword(p, high, n)
409 char *p, *high;
410 int n;
411 {
412 p++;
413
414 while (n--) {
415 while ((p < high) && isspace((unsigned char) *p))
416 p++;
417
418 if (isalnum((unsigned char) *p))
419 while ((p < high) && isalnum((unsigned char) *p))
420 p++;
421 else
422 while ((p < high) && !(isspace((unsigned char) *p) ||
423 isalnum((unsigned char) *p)))
424 p++;
425 }
426 p--;
427 return p;
428 }
429
430 /* ch_init():
431 * Initialize the character editor
432 */
433 protected int
434 ch_init(el)
435 EditLine *el;
436 {
437 el->el_line.buffer = (char *) el_malloc(EL_BUFSIZ);
438 (void) memset(el->el_line.buffer, 0, EL_BUFSIZ);
439 el->el_line.cursor = el->el_line.buffer;
440 el->el_line.lastchar = el->el_line.buffer;
441 el->el_line.limit = &el->el_line.buffer[EL_BUFSIZ - 2];
442
443 el->el_chared.c_undo.buf = (char *) el_malloc(EL_BUFSIZ);
444 (void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ);
445 el->el_chared.c_undo.action = NOP;
446 el->el_chared.c_undo.isize = 0;
447 el->el_chared.c_undo.dsize = 0;
448 el->el_chared.c_undo.ptr = el->el_line.buffer;
449
450 el->el_chared.c_vcmd.action = NOP;
451 el->el_chared.c_vcmd.pos = el->el_line.buffer;
452 el->el_chared.c_vcmd.ins = el->el_line.buffer;
453
454 el->el_chared.c_kill.buf = (char *) el_malloc(EL_BUFSIZ);
455 (void) memset(el->el_chared.c_kill.buf, 0, EL_BUFSIZ);
456 el->el_chared.c_kill.mark = el->el_line.buffer;
457 el->el_chared.c_kill.last = el->el_chared.c_kill.buf;
458
459 el->el_map.current = el->el_map.key;
460
461 el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */
462 el->el_state.doingarg = 0;
463 el->el_state.metanext = 0;
464 el->el_state.argument = 1;
465 el->el_state.lastcmd = ED_UNASSIGNED;
466
467 el->el_chared.c_macro.nline = NULL;
468 el->el_chared.c_macro.level = -1;
469 el->el_chared.c_macro.macro = (char **) el_malloc(EL_MAXMACRO *
470 sizeof(char *));
471 return 0;
472 }
473
474 /* ch_reset():
475 * Reset the character editor
476 */
477 protected void
478 ch_reset(el)
479 EditLine *el;
480 {
481 el->el_line.cursor = el->el_line.buffer;
482 el->el_line.lastchar = el->el_line.buffer;
483
484 el->el_chared.c_undo.action = NOP;
485 el->el_chared.c_undo.isize = 0;
486 el->el_chared.c_undo.dsize = 0;
487 el->el_chared.c_undo.ptr = el->el_line.buffer;
488
489 el->el_chared.c_vcmd.action = NOP;
490 el->el_chared.c_vcmd.pos = el->el_line.buffer;
491 el->el_chared.c_vcmd.ins = el->el_line.buffer;
492
493 el->el_chared.c_kill.mark = el->el_line.buffer;
494
495 el->el_map.current = el->el_map.key;
496
497 el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */
498 el->el_state.doingarg = 0;
499 el->el_state.metanext = 0;
500 el->el_state.argument = 1;
501 el->el_state.lastcmd = ED_UNASSIGNED;
502
503 el->el_chared.c_macro.level = -1;
504
505 el->el_history.eventno = 0;
506 }
507
508
509 /* ch_end():
510 * Free the data structures used by the editor
511 */
512 protected void
513 ch_end(el)
514 EditLine *el;
515 {
516 el_free((ptr_t) el->el_line.buffer);
517 el->el_line.buffer = NULL;
518 el->el_line.limit = NULL;
519 el_free((ptr_t) el->el_chared.c_undo.buf);
520 el->el_chared.c_undo.buf = NULL;
521 el_free((ptr_t) el->el_chared.c_kill.buf);
522 el->el_chared.c_kill.buf = NULL;
523 el_free((ptr_t) el->el_chared.c_macro.macro);
524 el->el_chared.c_macro.macro = NULL;
525 ch_reset(el);
526 }
527
528
529 /* el_insertstr():
530 * Insert string at cursorI
531 */
532 public int
533 el_insertstr(el, s)
534 EditLine *el;
535 char *s;
536 {
537 int len;
538
539 if ((len = strlen(s)) == 0)
540 return -1;
541 if (el->el_line.lastchar + len >= el->el_line.limit)
542 return -1;
543
544 c_insert(el, len);
545 while (*s)
546 *el->el_line.cursor++ = *s++;
547 return 0;
548 }
549
550
551 /* el_deletestr():
552 * Delete num characters before the cursor
553 */
554 public void
555 el_deletestr(el, n)
556 EditLine *el;
557 int n;
558 {
559 if (n <= 0)
560 return;
561
562 if (el->el_line.cursor < &el->el_line.buffer[n])
563 return;
564
565 c_delbefore(el, n); /* delete before dot */
566 el->el_line.cursor -= n;
567 if (el->el_line.cursor < el->el_line.buffer)
568 el->el_line.cursor = el->el_line.buffer;
569 }
570
571 /* c_gets():
572 * Get a string
573 */
574 protected int
575 c_gets(el, buf)
576 EditLine *el;
577 char *buf;
578 {
579 char ch;
580 int len = 0;
581
582 for (ch = 0; ch == 0;) {
583 if (el_getc(el, &ch) != 1)
584 return ed_end_of_file(el, 0);
585 switch (ch) {
586 case 0010: /* Delete and backspace */
587 case 0177:
588 if (len > 1) {
589 *el->el_line.cursor-- = '\0';
590 el->el_line.lastchar = el->el_line.cursor;
591 buf[len--] = '\0';
592 }
593 else {
594 el->el_line.buffer[0] = '\0';
595 el->el_line.lastchar = el->el_line.buffer;
596 el->el_line.cursor = el->el_line.buffer;
597 return CC_REFRESH;
598 }
599 re_refresh(el);
600 ch = 0;
601 break;
602
603 case 0033: /* ESC */
604 case '\r': /* Newline */
605 case '\n':
606 break;
607
608 default:
609 if (len >= EL_BUFSIZ)
610 term_beep(el);
611 else {
612 buf[len++] = ch;
613 *el->el_line.cursor++ = ch;
614 el->el_line.lastchar = el->el_line.cursor;
615 }
616 re_refresh(el);
617 ch = 0;
618 break;
619 }
620 }
621 buf[len] = ch;
622 return len;
623 }
624
625
626 /* c_hpos():
627 * Return the current horizontal position of the cursor
628 */
629 protected int
630 c_hpos(el)
631 EditLine *el;
632 {
633 char *ptr;
634
635 /*
636 * Find how many characters till the beginning of this line.
637 */
638 if (el->el_line.cursor == el->el_line.buffer)
639 return 0;
640 else {
641 for (ptr = el->el_line.cursor - 1;
642 ptr >= el->el_line.buffer && *ptr != '\n';
643 ptr--)
644 continue;
645 return el->el_line.cursor - ptr - 1;
646 }
647 }
648