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