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