chared.c revision 1.4 1 /* $NetBSD: chared.c,v 1.4 1998/02/03 19:12:37 perry 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.4 1998/02/03 19:12:37 perry 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, size;
63 char *ptr;
64 {
65 c_undo_t *vu = &el->el_chared.c_undo;
66 vu->action = action;
67 vu->ptr = ptr;
68 vu->isize = size;
69 (void) memcpy(vu->buf, vu->ptr, size);
70 #ifdef DEBUG_UNDO
71 (void) fprintf(el->el_errfile, "Undo buffer \"%s\" size = +%d -%d\n",
72 vu->ptr, vu->isize, vu->dsize);
73 #endif
74 }
75
76
77 /* c_insert():
78 * Insert num characters
79 */
80 protected void
81 c_insert(el, num)
82 EditLine *el;
83 int num;
84 {
85 char *cp;
86
87 if (el->el_line.lastchar + num >= el->el_line.limit)
88 return; /* can't go past end of buffer */
89
90 if (el->el_line.cursor < el->el_line.lastchar) {
91 /* if I must move chars */
92 for (cp = el->el_line.lastchar; cp >= el->el_line.cursor; cp--)
93 cp[num] = *cp;
94 }
95 el->el_line.lastchar += num;
96 } /* end c_insert */
97
98
99 /* c_delafter():
100 * Delete num characters after the cursor
101 */
102 protected void
103 c_delafter(el, num)
104 EditLine *el;
105 int num;
106 {
107
108 if (el->el_line.cursor + num > el->el_line.lastchar)
109 num = el->el_line.lastchar - el->el_line.cursor;
110
111 if (num > 0) {
112 char *cp;
113
114 if (el->el_map.current != el->el_map.emacs)
115 cv_undo(el, INSERT, num, el->el_line.cursor);
116
117 for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
118 *cp = cp[num];
119
120 el->el_line.lastchar -= num;
121 }
122 }
123
124
125 /* c_delbefore():
126 * Delete num characters before the cursor
127 */
128 protected void
129 c_delbefore(el, num)
130 EditLine *el;
131 int num;
132 {
133
134 if (el->el_line.cursor - num < el->el_line.buffer)
135 num = el->el_line.cursor - el->el_line.buffer;
136
137 if (num > 0) {
138 char *cp;
139
140 if (el->el_map.current != el->el_map.emacs)
141 cv_undo(el, INSERT, num, el->el_line.cursor - num);
142
143 for (cp = el->el_line.cursor - num; cp <= el->el_line.lastchar; cp++)
144 *cp = cp[num];
145
146 el->el_line.lastchar -= num;
147 }
148 }
149
150
151 /* ce__isword():
152 * Return if p is part of a word according to emacs
153 */
154 protected int
155 ce__isword(p)
156 int p;
157 {
158 return isalpha(p) || isdigit(p) || strchr("*?_-.[]~=", p) != NULL;
159 }
160
161
162 /* cv__isword():
163 * Return if p is part of a word according to vi
164 */
165 protected int
166 cv__isword(p)
167 int p;
168 {
169 return !isspace(p);
170 }
171
172
173 /* c__prev_word():
174 * Find the previous word
175 */
176 protected char *
177 c__prev_word(p, low, n, wtest)
178 char *p, *low;
179 int n;
180 int (*wtest) __P((int));
181 {
182 p--;
183
184 while (n--) {
185 while ((p >= low) && !(*wtest)((unsigned char) *p))
186 p--;
187 while ((p >= low) && (*wtest)((unsigned char) *p))
188 p--;
189 }
190
191 /* cp now points to one character before the word */
192 p++;
193 if (p < low)
194 p = low;
195 /* cp now points where we want it */
196 return p;
197 }
198
199
200 /* c__next_word():
201 * Find the next word
202 */
203 protected char *
204 c__next_word(p, high, n, wtest)
205 char *p, *high;
206 int n;
207 int (*wtest) __P((int));
208 {
209 while (n--) {
210 while ((p < high) && !(*wtest)((unsigned char) *p))
211 p++;
212 while ((p < high) && (*wtest)((unsigned char) *p))
213 p++;
214 }
215 if (p > high)
216 p = high;
217 /* p now points where we want it */
218 return p;
219 }
220
221 /* cv_next_word():
222 * Find the next word vi style
223 */
224 protected char *
225 cv_next_word(el, p, high, n, wtest)
226 EditLine *el;
227 char *p, *high;
228 int n;
229 int (*wtest) __P((int));
230 {
231 int test;
232
233 while (n--) {
234 test = (*wtest)((unsigned char) *p);
235 while ((p < high) && (*wtest)((unsigned char) *p) == test)
236 p++;
237 /*
238 * vi historically deletes with cw only the word preserving the
239 * trailing whitespace! This is not what 'w' does..
240 */
241 if (el->el_chared.c_vcmd.action != (DELETE|INSERT))
242 while ((p < high) && isspace((unsigned char) *p))
243 p++;
244 }
245
246 /* p now points where we want it */
247 if (p > high)
248 return high;
249 else
250 return p;
251 }
252
253
254 /* cv_prev_word():
255 * Find the previous word vi style
256 */
257 protected char *
258 cv_prev_word(el, p, low, n, wtest)
259 EditLine *el;
260 char *p, *low;
261 int n;
262 int (*wtest) __P((int));
263 {
264 int test;
265
266 while (n--) {
267 p--;
268 /*
269 * vi historically deletes with cb only the word preserving the
270 * leading whitespace! This is not what 'b' does..
271 */
272 if (el->el_chared.c_vcmd.action != (DELETE|INSERT))
273 while ((p > low) && isspace((unsigned char) *p))
274 p--;
275 test = (*wtest)((unsigned char) *p);
276 while ((p >= low) && (*wtest)((unsigned char) *p) == test)
277 p--;
278 p++;
279 while (isspace((unsigned char) *p))
280 p++;
281 }
282
283 /* p now points where we want it */
284 if (p < low)
285 return low;
286 else
287 return p;
288 }
289
290
291 #ifdef notdef
292 /* c__number():
293 * Ignore character p points to, return number appearing after that.
294 * A '$' by itself means a big number; "$-" is for negative; '^' means 1.
295 * Return p pointing to last char used.
296 */
297 protected char *
298 c__number(p, num, dval)
299 char *p; /* character position */
300 int *num; /* Return value */
301 int dval; /* dval is the number to subtract from like $-3 */
302 {
303 int i;
304 int sign = 1;
305
306 if (*++p == '^') {
307 *num = 1;
308 return p;
309 }
310 if (*p == '$') {
311 if (*++p != '-') {
312 *num = 0x7fffffff; /* Handle $ */
313 return --p;
314 }
315 sign = -1; /* Handle $- */
316 ++p;
317 }
318 for (i = 0; isdigit((unsigned char) *p); i = 10 * i + *p++ - '0')
319 continue;
320 *num = (sign < 0 ? dval - i : i);
321 return --p;
322 }
323 #endif
324
325 /* cv_delfini():
326 * Finish vi delete action
327 */
328 protected void
329 cv_delfini(el)
330 EditLine *el;
331 {
332 int size;
333 int oaction;
334
335 if (el->el_chared.c_vcmd.action & INSERT)
336 el->el_map.current = el->el_map.key;
337
338 oaction = el->el_chared.c_vcmd.action;
339 el->el_chared.c_vcmd.action = NOP;
340
341 if (el->el_chared.c_vcmd.pos == 0)
342 return;
343
344
345 if (el->el_line.cursor > el->el_chared.c_vcmd.pos) {
346 size = (int) (el->el_line.cursor - el->el_chared.c_vcmd.pos);
347 c_delbefore(el, size);
348 el->el_line.cursor = el->el_chared.c_vcmd.pos;
349 re_refresh_cursor(el);
350 }
351 else if (el->el_line.cursor < el->el_chared.c_vcmd.pos) {
352 size = (int)(el->el_chared.c_vcmd.pos - el->el_line.cursor);
353 c_delafter(el, size);
354 }
355 else {
356 size = 1;
357 c_delafter(el, size);
358 }
359 switch (oaction) {
360 case DELETE|INSERT:
361 el->el_chared.c_undo.action = DELETE|INSERT;
362 break;
363 case DELETE:
364 el->el_chared.c_undo.action = INSERT;
365 break;
366 case NOP:
367 case INSERT:
368 default:
369 abort();
370 break;
371 }
372
373
374 el->el_chared.c_undo.ptr = el->el_line.cursor;
375 el->el_chared.c_undo.dsize = size;
376 }
377
378
379 #ifdef notdef
380 /* ce__endword():
381 * Go to the end of this word according to emacs
382 */
383 protected char *
384 ce__endword(p, high, n)
385 char *p, *high;
386 int n;
387 {
388 p++;
389
390 while (n--) {
391 while ((p < high) && isspace((unsigned char) *p))
392 p++;
393 while ((p < high) && !isspace((unsigned char) *p))
394 p++;
395 }
396
397 p--;
398 return p;
399 }
400 #endif
401
402
403 /* cv__endword():
404 * Go to the end of this word according to vi
405 */
406 protected char *
407 cv__endword(p, high, n)
408 char *p, *high;
409 int n;
410 {
411 p++;
412
413 while (n--) {
414 while ((p < high) && isspace((unsigned char) *p))
415 p++;
416
417 if (isalnum((unsigned char) *p))
418 while ((p < high) && isalnum((unsigned char) *p))
419 p++;
420 else
421 while ((p < high) && !(isspace((unsigned char) *p) ||
422 isalnum((unsigned char) *p)))
423 p++;
424 }
425 p--;
426 return p;
427 }
428
429 /* ch_init():
430 * Initialize the character editor
431 */
432 protected int
433 ch_init(el)
434 EditLine *el;
435 {
436 el->el_line.buffer = (char *) el_malloc(EL_BUFSIZ);
437 (void) memset(el->el_line.buffer, 0, EL_BUFSIZ);
438 el->el_line.cursor = el->el_line.buffer;
439 el->el_line.lastchar = el->el_line.buffer;
440 el->el_line.limit = &el->el_line.buffer[EL_BUFSIZ - 2];
441
442 el->el_chared.c_undo.buf = (char *) el_malloc(EL_BUFSIZ);
443 (void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ);
444 el->el_chared.c_undo.action = NOP;
445 el->el_chared.c_undo.isize = 0;
446 el->el_chared.c_undo.dsize = 0;
447 el->el_chared.c_undo.ptr = el->el_line.buffer;
448
449 el->el_chared.c_vcmd.action = NOP;
450 el->el_chared.c_vcmd.pos = el->el_line.buffer;
451 el->el_chared.c_vcmd.ins = el->el_line.buffer;
452
453 el->el_chared.c_kill.buf = (char *) el_malloc(EL_BUFSIZ);
454 (void) memset(el->el_chared.c_kill.buf, 0, EL_BUFSIZ);
455 el->el_chared.c_kill.mark = el->el_line.buffer;
456 el->el_chared.c_kill.last = el->el_chared.c_kill.buf;
457
458 el->el_map.current = el->el_map.key;
459
460 el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */
461 el->el_state.doingarg = 0;
462 el->el_state.metanext = 0;
463 el->el_state.argument = 1;
464 el->el_state.lastcmd = ED_UNASSIGNED;
465
466 el->el_chared.c_macro.nline = NULL;
467 el->el_chared.c_macro.level = -1;
468 el->el_chared.c_macro.macro = (char **) el_malloc(EL_MAXMACRO *
469 sizeof(char *));
470 return 0;
471 }
472
473 /* ch_reset():
474 * Reset the character editor
475 */
476 protected void
477 ch_reset(el)
478 EditLine *el;
479 {
480 el->el_line.cursor = el->el_line.buffer;
481 el->el_line.lastchar = el->el_line.buffer;
482
483 el->el_chared.c_undo.action = NOP;
484 el->el_chared.c_undo.isize = 0;
485 el->el_chared.c_undo.dsize = 0;
486 el->el_chared.c_undo.ptr = el->el_line.buffer;
487
488 el->el_chared.c_vcmd.action = NOP;
489 el->el_chared.c_vcmd.pos = el->el_line.buffer;
490 el->el_chared.c_vcmd.ins = el->el_line.buffer;
491
492 el->el_chared.c_kill.mark = el->el_line.buffer;
493
494 el->el_map.current = el->el_map.key;
495
496 el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */
497 el->el_state.doingarg = 0;
498 el->el_state.metanext = 0;
499 el->el_state.argument = 1;
500 el->el_state.lastcmd = ED_UNASSIGNED;
501
502 el->el_chared.c_macro.level = -1;
503
504 el->el_history.eventno = 0;
505 }
506
507
508 /* ch_end():
509 * Free the data structures used by the editor
510 */
511 protected void
512 ch_end(el)
513 EditLine *el;
514 {
515 el_free((ptr_t) el->el_line.buffer);
516 el->el_line.buffer = NULL;
517 el->el_line.limit = NULL;
518 el_free((ptr_t) el->el_chared.c_undo.buf);
519 el->el_chared.c_undo.buf = NULL;
520 el_free((ptr_t) el->el_chared.c_kill.buf);
521 el->el_chared.c_kill.buf = NULL;
522 el_free((ptr_t) el->el_chared.c_macro.macro);
523 el->el_chared.c_macro.macro = NULL;
524 ch_reset(el);
525 }
526
527
528 /* el_insertstr():
529 * Insert string at cursorI
530 */
531 public int
532 el_insertstr(el, s)
533 EditLine *el;
534 char *s;
535 {
536 int len;
537
538 if ((len = strlen(s)) == 0)
539 return -1;
540 if (el->el_line.lastchar + len >= el->el_line.limit)
541 return -1;
542
543 c_insert(el, len);
544 while (*s)
545 *el->el_line.cursor++ = *s++;
546 return 0;
547 }
548
549
550 /* el_deletestr():
551 * Delete num characters before the cursor
552 */
553 public void
554 el_deletestr(el, n)
555 EditLine *el;
556 int n;
557 {
558 if (n <= 0)
559 return;
560
561 if (el->el_line.cursor < &el->el_line.buffer[n])
562 return;
563
564 c_delbefore(el, n); /* delete before dot */
565 el->el_line.cursor -= n;
566 if (el->el_line.cursor < el->el_line.buffer)
567 el->el_line.cursor = el->el_line.buffer;
568 }
569
570 /* c_gets():
571 * Get a string
572 */
573 protected int
574 c_gets(el, buf)
575 EditLine *el;
576 char *buf;
577 {
578 char ch;
579 int len = 0;
580
581 for (ch = 0; ch == 0;) {
582 if (el_getc(el, &ch) != 1)
583 return ed_end_of_file(el, 0);
584 switch (ch) {
585 case 0010: /* Delete and backspace */
586 case 0177:
587 if (len > 1) {
588 *el->el_line.cursor-- = '\0';
589 el->el_line.lastchar = el->el_line.cursor;
590 buf[len--] = '\0';
591 }
592 else {
593 el->el_line.buffer[0] = '\0';
594 el->el_line.lastchar = el->el_line.buffer;
595 el->el_line.cursor = el->el_line.buffer;
596 return CC_REFRESH;
597 }
598 re_refresh(el);
599 ch = 0;
600 break;
601
602 case 0033: /* ESC */
603 case '\r': /* Newline */
604 case '\n':
605 break;
606
607 default:
608 if (len >= EL_BUFSIZ)
609 term_beep(el);
610 else {
611 buf[len++] = ch;
612 *el->el_line.cursor++ = ch;
613 el->el_line.lastchar = el->el_line.cursor;
614 }
615 re_refresh(el);
616 ch = 0;
617 break;
618 }
619 }
620 buf[len] = ch;
621 return len;
622 }
623
624
625 /* c_hpos():
626 * Return the current horizontal position of the cursor
627 */
628 protected int
629 c_hpos(el)
630 EditLine *el;
631 {
632 char *ptr;
633
634 /*
635 * Find how many characters till the beginning of this line.
636 */
637 if (el->el_line.cursor == el->el_line.buffer)
638 return 0;
639 else {
640 for (ptr = el->el_line.cursor - 1;
641 ptr >= el->el_line.buffer && *ptr != '\n';
642 ptr--)
643 continue;
644 return el->el_line.cursor - ptr - 1;
645 }
646 }
647