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