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