xref: /trueos/lib/libedit/chared.c (revision ede42824618710ffa9ac08c805d8bf39bd5661ce)
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. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  *	$NetBSD: chared.c,v 1.27 2009/02/15 21:55:23 christos Exp $
33  */
34 
35 #if !defined(lint) && !defined(SCCSID)
36 static char sccsid[] = "@(#)chared.c	8.1 (Berkeley) 6/4/93";
37 #endif /* not lint && not SCCSID */
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40 
41 /*
42  * chared.c: Character editor utilities
43  */
44 #include "sys.h"
45 
46 #include <stdlib.h>
47 #include "el.h"
48 
49 private void ch__clearmacro(EditLine *);
50 
51 /* value to leave unused in line buffer */
52 #define	EL_LEAVE	2
53 
54 /* cv_undo():
55  *	Handle state for the vi undo command
56  */
57 protected void
cv_undo(EditLine * el)58 cv_undo(EditLine *el)
59 {
60 	c_undo_t *vu = &el->el_chared.c_undo;
61 	c_redo_t *r = &el->el_chared.c_redo;
62 	size_t size;
63 
64 	/* Save entire line for undo */
65 	size = el->el_line.lastchar - el->el_line.buffer;
66 	vu->len = size;
67 	vu->cursor = (int)(el->el_line.cursor - el->el_line.buffer);
68 	memcpy(vu->buf, el->el_line.buffer, size);
69 
70 	/* save command info for redo */
71 	r->count = el->el_state.doingarg ? el->el_state.argument : 0;
72 	r->action = el->el_chared.c_vcmd.action;
73 	r->pos = r->buf;
74 	r->cmd = el->el_state.thiscmd;
75 	r->ch = el->el_state.thisch;
76 }
77 
78 /* cv_yank():
79  *	Save yank/delete data for paste
80  */
81 protected void
cv_yank(EditLine * el,const char * ptr,int size)82 cv_yank(EditLine *el, const char *ptr, int size)
83 {
84 	c_kill_t *k = &el->el_chared.c_kill;
85 
86 	memcpy(k->buf, ptr, (size_t)size);
87 	k->last = k->buf + size;
88 }
89 
90 
91 /* c_insert():
92  *	Insert num characters
93  */
94 protected void
c_insert(EditLine * el,int num)95 c_insert(EditLine *el, int num)
96 {
97 	char *cp;
98 
99 	if (el->el_line.lastchar + num >= el->el_line.limit) {
100 		if (!ch_enlargebufs(el, (size_t)num))
101 			return;		/* can't go past end of buffer */
102 	}
103 
104 	if (el->el_line.cursor < el->el_line.lastchar) {
105 		/* if I must move chars */
106 		for (cp = el->el_line.lastchar; cp >= el->el_line.cursor; cp--)
107 			cp[num] = *cp;
108 	}
109 	el->el_line.lastchar += num;
110 }
111 
112 
113 /* c_delafter():
114  *	Delete num characters after the cursor
115  */
116 protected void
c_delafter(EditLine * el,int num)117 c_delafter(EditLine *el, int num)
118 {
119 
120 	if (el->el_line.cursor + num > el->el_line.lastchar)
121 		num = (int)(el->el_line.lastchar - el->el_line.cursor);
122 
123 	if (el->el_map.current != el->el_map.emacs) {
124 		cv_undo(el);
125 		cv_yank(el, el->el_line.cursor, num);
126 	}
127 
128 	if (num > 0) {
129 		char *cp;
130 
131 		for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
132 			*cp = cp[num];
133 
134 		el->el_line.lastchar -= num;
135 	}
136 }
137 
138 
139 /* c_delafter1():
140  *	Delete the character after the cursor, do not yank
141  */
142 protected void
c_delafter1(EditLine * el)143 c_delafter1(EditLine *el)
144 {
145 	char *cp;
146 
147 	for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
148 		*cp = cp[1];
149 
150 	el->el_line.lastchar--;
151 }
152 
153 
154 /* c_delbefore():
155  *	Delete num characters before the cursor
156  */
157 protected void
c_delbefore(EditLine * el,int num)158 c_delbefore(EditLine *el, int num)
159 {
160 
161 	if (el->el_line.cursor - num < el->el_line.buffer)
162 		num = (int)(el->el_line.cursor - el->el_line.buffer);
163 
164 	if (el->el_map.current != el->el_map.emacs) {
165 		cv_undo(el);
166 		cv_yank(el, el->el_line.cursor - num, num);
167 	}
168 
169 	if (num > 0) {
170 		char *cp;
171 
172 		for (cp = el->el_line.cursor - num;
173 		    cp <= el->el_line.lastchar;
174 		    cp++)
175 			*cp = cp[num];
176 
177 		el->el_line.lastchar -= num;
178 	}
179 }
180 
181 
182 /* c_delbefore1():
183  *	Delete the character before the cursor, do not yank
184  */
185 protected void
c_delbefore1(EditLine * el)186 c_delbefore1(EditLine *el)
187 {
188 	char *cp;
189 
190 	for (cp = el->el_line.cursor - 1; cp <= el->el_line.lastchar; cp++)
191 		*cp = cp[1];
192 
193 	el->el_line.lastchar--;
194 }
195 
196 
197 /* ce__isword():
198  *	Return if p is part of a word according to emacs
199  */
200 protected int
ce__isword(int p)201 ce__isword(int p)
202 {
203 	return (isalnum(p) || strchr("*?_-.[]~=", p) != NULL);
204 }
205 
206 
207 /* cv__isword():
208  *	Return if p is part of a word according to vi
209  */
210 protected int
cv__isword(int p)211 cv__isword(int p)
212 {
213 	if (isalnum(p) || p == '_')
214 		return 1;
215 	if (isgraph(p))
216 		return 2;
217 	return 0;
218 }
219 
220 
221 /* cv__isWord():
222  *	Return if p is part of a big word according to vi
223  */
224 protected int
cv__isWord(int p)225 cv__isWord(int p)
226 {
227 	return (!isspace(p));
228 }
229 
230 
231 /* c__prev_word():
232  *	Find the previous word
233  */
234 protected char *
c__prev_word(char * p,char * low,int n,int (* wtest)(int))235 c__prev_word(char *p, char *low, int n, int (*wtest)(int))
236 {
237 	p--;
238 
239 	while (n--) {
240 		while ((p >= low) && !(*wtest)((unsigned char) *p))
241 			p--;
242 		while ((p >= low) && (*wtest)((unsigned char) *p))
243 			p--;
244 	}
245 
246 	/* cp now points to one character before the word */
247 	p++;
248 	if (p < low)
249 		p = low;
250 	/* cp now points where we want it */
251 	return (p);
252 }
253 
254 
255 /* c__next_word():
256  *	Find the next word
257  */
258 protected char *
c__next_word(char * p,char * high,int n,int (* wtest)(int))259 c__next_word(char *p, char *high, int n, int (*wtest)(int))
260 {
261 	while (n--) {
262 		while ((p < high) && !(*wtest)((unsigned char) *p))
263 			p++;
264 		while ((p < high) && (*wtest)((unsigned char) *p))
265 			p++;
266 	}
267 	if (p > high)
268 		p = high;
269 	/* p now points where we want it */
270 	return (p);
271 }
272 
273 /* cv_next_word():
274  *	Find the next word vi style
275  */
276 protected char *
cv_next_word(EditLine * el,char * p,char * high,int n,int (* wtest)(int))277 cv_next_word(EditLine *el, char *p, char *high, int n, int (*wtest)(int))
278 {
279 	int test;
280 
281 	while (n--) {
282 		test = (*wtest)((unsigned char) *p);
283 		while ((p < high) && (*wtest)((unsigned char) *p) == test)
284 			p++;
285 		/*
286 		 * vi historically deletes with cw only the word preserving the
287 		 * trailing whitespace! This is not what 'w' does..
288 		 */
289 		if (n || el->el_chared.c_vcmd.action != (DELETE|INSERT))
290 			while ((p < high) && isspace((unsigned char) *p))
291 				p++;
292 	}
293 
294 	/* p now points where we want it */
295 	if (p > high)
296 		return (high);
297 	else
298 		return (p);
299 }
300 
301 
302 /* cv_prev_word():
303  *	Find the previous word vi style
304  */
305 protected char *
cv_prev_word(char * p,char * low,int n,int (* wtest)(int))306 cv_prev_word(char *p, char *low, int n, int (*wtest)(int))
307 {
308 	int test;
309 
310 	p--;
311 	while (n--) {
312 		while ((p > low) && isspace((unsigned char) *p))
313 			p--;
314 		test = (*wtest)((unsigned char) *p);
315 		while ((p >= low) && (*wtest)((unsigned char) *p) == test)
316 			p--;
317 	}
318 	p++;
319 
320 	/* p now points where we want it */
321 	if (p < low)
322 		return (low);
323 	else
324 		return (p);
325 }
326 
327 
328 #ifdef notdef
329 /* c__number():
330  *	Ignore character p points to, return number appearing after that.
331  * 	A '$' by itself means a big number; "$-" is for negative; '^' means 1.
332  * 	Return p pointing to last char used.
333  */
334 protected char *
c__number(char * p,int * num,int dval)335 c__number(
336     char *p,	/* character position */
337     int *num,	/* Return value	*/
338     int dval)	/* dval is the number to subtract from like $-3 */
339 {
340 	int i;
341 	int sign = 1;
342 
343 	if (*++p == '^') {
344 		*num = 1;
345 		return (p);
346 	}
347 	if (*p == '$') {
348 		if (*++p != '-') {
349 			*num = 0x7fffffff;	/* Handle $ */
350 			return (--p);
351 		}
352 		sign = -1;			/* Handle $- */
353 		++p;
354 	}
355 	for (i = 0; isdigit((unsigned char) *p); i = 10 * i + *p++ - '0')
356 		continue;
357 	*num = (sign < 0 ? dval - i : i);
358 	return (--p);
359 }
360 #endif
361 
362 /* cv_delfini():
363  *	Finish vi delete action
364  */
365 protected void
cv_delfini(EditLine * el)366 cv_delfini(EditLine *el)
367 {
368 	int size;
369 	int action = el->el_chared.c_vcmd.action;
370 
371 	if (action & INSERT)
372 		el->el_map.current = el->el_map.key;
373 
374 	if (el->el_chared.c_vcmd.pos == 0)
375 		/* sanity */
376 		return;
377 
378 	size = (int)(el->el_line.cursor - el->el_chared.c_vcmd.pos);
379 	if (size == 0)
380 		size = 1;
381 	el->el_line.cursor = el->el_chared.c_vcmd.pos;
382 	if (action & YANK) {
383 		if (size > 0)
384 			cv_yank(el, el->el_line.cursor, size);
385 		else
386 			cv_yank(el, el->el_line.cursor + size, -size);
387 	} else {
388 		if (size > 0) {
389 			c_delafter(el, size);
390 			re_refresh_cursor(el);
391 		} else  {
392 			c_delbefore(el, -size);
393 			el->el_line.cursor += size;
394 		}
395 	}
396 	el->el_chared.c_vcmd.action = NOP;
397 }
398 
399 
400 #ifdef notdef
401 /* ce__endword():
402  *	Go to the end of this word according to emacs
403  */
404 protected char *
ce__endword(char * p,char * high,int n)405 ce__endword(char *p, char *high, int n)
406 {
407 	p++;
408 
409 	while (n--) {
410 		while ((p < high) && isspace((unsigned char) *p))
411 			p++;
412 		while ((p < high) && !isspace((unsigned char) *p))
413 			p++;
414 	}
415 
416 	p--;
417 	return (p);
418 }
419 #endif
420 
421 
422 /* cv__endword():
423  *	Go to the end of this word according to vi
424  */
425 protected char *
cv__endword(char * p,char * high,int n,int (* wtest)(int))426 cv__endword(char *p, char *high, int n, int (*wtest)(int))
427 {
428 	int test;
429 
430 	p++;
431 
432 	while (n--) {
433 		while ((p < high) && isspace((unsigned char) *p))
434 			p++;
435 
436 		test = (*wtest)((unsigned char) *p);
437 		while ((p < high) && (*wtest)((unsigned char) *p) == test)
438 			p++;
439 	}
440 	p--;
441 	return (p);
442 }
443 
444 /* ch_init():
445  *	Initialize the character editor
446  */
447 protected int
ch_init(EditLine * el)448 ch_init(EditLine *el)
449 {
450 	c_macro_t *ma = &el->el_chared.c_macro;
451 
452 	el->el_line.buffer		= (char *) el_malloc(EL_BUFSIZ);
453 	if (el->el_line.buffer == NULL)
454 		return (-1);
455 
456 	(void) memset(el->el_line.buffer, 0, EL_BUFSIZ);
457 	el->el_line.cursor		= el->el_line.buffer;
458 	el->el_line.lastchar		= el->el_line.buffer;
459 	el->el_line.limit		= &el->el_line.buffer[EL_BUFSIZ - EL_LEAVE];
460 
461 	el->el_chared.c_undo.buf	= (char *) el_malloc(EL_BUFSIZ);
462 	if (el->el_chared.c_undo.buf == NULL)
463 		return (-1);
464 	(void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ);
465 	el->el_chared.c_undo.len	= -1;
466 	el->el_chared.c_undo.cursor	= 0;
467 	el->el_chared.c_redo.buf	= (char *) el_malloc(EL_BUFSIZ);
468 	if (el->el_chared.c_redo.buf == NULL)
469 		return (-1);
470 	el->el_chared.c_redo.pos	= el->el_chared.c_redo.buf;
471 	el->el_chared.c_redo.lim	= el->el_chared.c_redo.buf + EL_BUFSIZ;
472 	el->el_chared.c_redo.cmd	= ED_UNASSIGNED;
473 
474 	el->el_chared.c_vcmd.action	= NOP;
475 	el->el_chared.c_vcmd.pos	= el->el_line.buffer;
476 
477 	el->el_chared.c_kill.buf	= (char *) el_malloc(EL_BUFSIZ);
478 	if (el->el_chared.c_kill.buf == NULL)
479 		return (-1);
480 	(void) memset(el->el_chared.c_kill.buf, 0, EL_BUFSIZ);
481 	el->el_chared.c_kill.mark	= el->el_line.buffer;
482 	el->el_chared.c_kill.last	= el->el_chared.c_kill.buf;
483 
484 	el->el_map.current		= el->el_map.key;
485 
486 	el->el_state.inputmode		= MODE_INSERT; /* XXX: save a default */
487 	el->el_state.doingarg		= 0;
488 	el->el_state.metanext		= 0;
489 	el->el_state.argument		= 1;
490 	el->el_state.lastcmd		= ED_UNASSIGNED;
491 
492 	ma->level	= -1;
493 	ma->offset	= 0;
494 	ma->macro	= (char **) el_malloc(EL_MAXMACRO * sizeof(char *));
495 	if (ma->macro == NULL)
496 		return (-1);
497 	return (0);
498 }
499 
500 /* ch_reset():
501  *	Reset the character editor
502  */
503 protected void
ch_reset(EditLine * el,int mclear)504 ch_reset(EditLine *el, int mclear)
505 {
506 	el->el_line.cursor		= el->el_line.buffer;
507 	el->el_line.lastchar		= el->el_line.buffer;
508 
509 	el->el_chared.c_undo.len	= -1;
510 	el->el_chared.c_undo.cursor	= 0;
511 
512 	el->el_chared.c_vcmd.action	= NOP;
513 	el->el_chared.c_vcmd.pos	= el->el_line.buffer;
514 
515 	el->el_chared.c_kill.mark	= el->el_line.buffer;
516 
517 	el->el_map.current		= el->el_map.key;
518 
519 	el->el_state.inputmode		= MODE_INSERT; /* XXX: save a default */
520 	el->el_state.doingarg		= 0;
521 	el->el_state.metanext		= 0;
522 	el->el_state.argument		= 1;
523 	el->el_state.lastcmd		= ED_UNASSIGNED;
524 
525 	el->el_history.eventno		= 0;
526 
527 	if (mclear)
528 		ch__clearmacro(el);
529 }
530 
531 private void
ch__clearmacro(EditLine * el)532 ch__clearmacro(EditLine *el)
533 {
534 	c_macro_t *ma = &el->el_chared.c_macro;
535 	while (ma->level >= 0)
536 		el_free((ptr_t)ma->macro[ma->level--]);
537 }
538 
539 /* ch_enlargebufs():
540  *	Enlarge line buffer to be able to hold twice as much characters.
541  *	Returns 1 if successful, 0 if not.
542  */
543 protected int
ch_enlargebufs(EditLine * el,size_t addlen)544 ch_enlargebufs(EditLine *el, size_t addlen)
545 {
546 	size_t sz, newsz;
547 	char *newbuffer, *oldbuf, *oldkbuf;
548 
549 	sz = el->el_line.limit - el->el_line.buffer + EL_LEAVE;
550 	newsz = sz * 2;
551 	/*
552 	 * If newly required length is longer than current buffer, we need
553 	 * to make the buffer big enough to hold both old and new stuff.
554 	 */
555 	if (addlen > sz) {
556 		while(newsz - sz < addlen)
557 			newsz *= 2;
558 	}
559 
560 	/*
561 	 * Reallocate line buffer.
562 	 */
563 	newbuffer = el_realloc(el->el_line.buffer, newsz);
564 	if (!newbuffer)
565 		return 0;
566 
567 	/* zero the newly added memory, leave old data in */
568 	(void) memset(&newbuffer[sz], 0, newsz - sz);
569 
570 	oldbuf = el->el_line.buffer;
571 
572 	el->el_line.buffer = newbuffer;
573 	el->el_line.cursor = newbuffer + (el->el_line.cursor - oldbuf);
574 	el->el_line.lastchar = newbuffer + (el->el_line.lastchar - oldbuf);
575 	/* don't set new size until all buffers are enlarged */
576 	el->el_line.limit  = &newbuffer[sz - EL_LEAVE];
577 
578 	/*
579 	 * Reallocate kill buffer.
580 	 */
581 	newbuffer = el_realloc(el->el_chared.c_kill.buf, newsz);
582 	if (!newbuffer)
583 		return 0;
584 
585 	/* zero the newly added memory, leave old data in */
586 	(void) memset(&newbuffer[sz], 0, newsz - sz);
587 
588 	oldkbuf = el->el_chared.c_kill.buf;
589 
590 	el->el_chared.c_kill.buf = newbuffer;
591 	el->el_chared.c_kill.last = newbuffer +
592 					(el->el_chared.c_kill.last - oldkbuf);
593 	el->el_chared.c_kill.mark = el->el_line.buffer +
594 					(el->el_chared.c_kill.mark - oldbuf);
595 
596 	/*
597 	 * Reallocate undo buffer.
598 	 */
599 	newbuffer = el_realloc(el->el_chared.c_undo.buf, newsz);
600 	if (!newbuffer)
601 		return 0;
602 
603 	/* zero the newly added memory, leave old data in */
604 	(void) memset(&newbuffer[sz], 0, newsz - sz);
605 	el->el_chared.c_undo.buf = newbuffer;
606 
607 	newbuffer = el_realloc(el->el_chared.c_redo.buf, newsz);
608 	if (!newbuffer)
609 		return 0;
610 	el->el_chared.c_redo.pos = newbuffer +
611 			(el->el_chared.c_redo.pos - el->el_chared.c_redo.buf);
612 	el->el_chared.c_redo.lim = newbuffer +
613 			(el->el_chared.c_redo.lim - el->el_chared.c_redo.buf);
614 	el->el_chared.c_redo.buf = newbuffer;
615 
616 	if (!hist_enlargebuf(el, sz, newsz))
617 		return 0;
618 
619 	/* Safe to set enlarged buffer size */
620 	el->el_line.limit  = &el->el_line.buffer[newsz - EL_LEAVE];
621 	return 1;
622 }
623 
624 /* ch_end():
625  *	Free the data structures used by the editor
626  */
627 protected void
ch_end(EditLine * el)628 ch_end(EditLine *el)
629 {
630 	el_free((ptr_t) el->el_line.buffer);
631 	el->el_line.buffer = NULL;
632 	el->el_line.limit = NULL;
633 	el_free((ptr_t) el->el_chared.c_undo.buf);
634 	el->el_chared.c_undo.buf = NULL;
635 	el_free((ptr_t) el->el_chared.c_redo.buf);
636 	el->el_chared.c_redo.buf = NULL;
637 	el->el_chared.c_redo.pos = NULL;
638 	el->el_chared.c_redo.lim = NULL;
639 	el->el_chared.c_redo.cmd = ED_UNASSIGNED;
640 	el_free((ptr_t) el->el_chared.c_kill.buf);
641 	el->el_chared.c_kill.buf = NULL;
642 	ch_reset(el, 1);
643 	el_free((ptr_t) el->el_chared.c_macro.macro);
644 	el->el_chared.c_macro.macro = NULL;
645 }
646 
647 
648 /* el_insertstr():
649  *	Insert string at cursorI
650  */
651 public int
el_insertstr(EditLine * el,const char * s)652 el_insertstr(EditLine *el, const char *s)
653 {
654 	size_t len;
655 
656 	if ((len = strlen(s)) == 0)
657 		return (-1);
658 	if (el->el_line.lastchar + len >= el->el_line.limit) {
659 		if (!ch_enlargebufs(el, len))
660 			return (-1);
661 	}
662 
663 	c_insert(el, (int)len);
664 	while (*s)
665 		*el->el_line.cursor++ = *s++;
666 	return (0);
667 }
668 
669 
670 /* el_deletestr():
671  *	Delete num characters before the cursor
672  */
673 public void
el_deletestr(EditLine * el,int n)674 el_deletestr(EditLine *el, int n)
675 {
676 	if (n <= 0)
677 		return;
678 
679 	if (el->el_line.cursor < &el->el_line.buffer[n])
680 		return;
681 
682 	c_delbefore(el, n);		/* delete before dot */
683 	el->el_line.cursor -= n;
684 	if (el->el_line.cursor < el->el_line.buffer)
685 		el->el_line.cursor = el->el_line.buffer;
686 }
687 
688 /* c_gets():
689  *	Get a string
690  */
691 protected int
c_gets(EditLine * el,char * buf,const char * prompt)692 c_gets(EditLine *el, char *buf, const char *prompt)
693 {
694 	char ch;
695 	ssize_t len;
696 	char *cp = el->el_line.buffer;
697 
698 	if (prompt) {
699 		len = strlen(prompt);
700 		memcpy(cp, prompt, (size_t)len);
701 		cp += len;
702 	}
703 	len = 0;
704 
705 	for (;;) {
706 		el->el_line.cursor = cp;
707 		*cp = ' ';
708 		el->el_line.lastchar = cp + 1;
709 		re_refresh(el);
710 
711 		if (el_getc(el, &ch) != 1) {
712 			ed_end_of_file(el, 0);
713 			len = -1;
714 			break;
715 		}
716 
717 		switch (ch) {
718 
719 		case '\010':	/* Delete and backspace */
720 		case '\177':
721 			if (len == 0) {
722 				len = -1;
723 				break;
724 			}
725 			cp--;
726 			continue;
727 
728 		case '\033':	/* ESC */
729 		case '\r':	/* Newline */
730 		case '\n':
731 			buf[len] = ch;
732 			break;
733 
734 		default:
735 			if (len >= EL_BUFSIZ - 16)
736 				term_beep(el);
737 			else {
738 				buf[len++] = ch;
739 				*cp++ = ch;
740 			}
741 			continue;
742 		}
743 		break;
744 	}
745 
746 	el->el_line.buffer[0] = '\0';
747 	el->el_line.lastchar = el->el_line.buffer;
748 	el->el_line.cursor = el->el_line.buffer;
749 	return (int)len;
750 }
751 
752 
753 /* c_hpos():
754  *	Return the current horizontal position of the cursor
755  */
756 protected int
c_hpos(EditLine * el)757 c_hpos(EditLine *el)
758 {
759 	char *ptr;
760 
761 	/*
762 	 * Find how many characters till the beginning of this line.
763 	 */
764 	if (el->el_line.cursor == el->el_line.buffer)
765 		return (0);
766 	else {
767 		for (ptr = el->el_line.cursor - 1;
768 		     ptr >= el->el_line.buffer && *ptr != '\n';
769 		     ptr--)
770 			continue;
771 		return (int)(el->el_line.cursor - ptr - 1);
772 	}
773 }
774