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