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