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