chared.c 16.6 KB
Newer Older
1
/*	$NetBSD: chared.c,v 1.26 2009/02/06 12:45:25 sketch Exp $	*/
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

/*-
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Christos Zoulas of Cornell University.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
18
 * 3. Neither the name of the University nor the names of its contributors
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

35 36 37 38 39 40 41
#include "config.h"
#if !defined(lint) && !defined(SCCSID)
#if 0
static char sccsid[] = "@(#)chared.c	8.1 (Berkeley) 6/4/93";
#else
#endif
#endif /* not lint && not SCCSID */
42 43 44 45 46 47 48

/*
 * chared.c: Character editor utilities
 */
#include <stdlib.h>
#include "el.h"

49 50
private void ch__clearmacro (EditLine *);

51 52 53 54 55 56 57
/* value to leave unused in line buffer */
#define	EL_LEAVE	2

/* cv_undo():
 *	Handle state for the vi undo command
 */
protected void
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
	unsigned int size;
63 64 65 66 67

	/* Save entire line for undo */
	size = el->el_line.lastchar - el->el_line.buffer;
	vu->len = size;
	vu->cursor = el->el_line.cursor - el->el_line.buffer;
68
	memcpy(vu->buf, el->el_line.buffer, size);
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87

	/* save command info for redo */
	r->count = el->el_state.doingarg ? el->el_state.argument : 0;
	r->action = el->el_chared.c_vcmd.action;
	r->pos = r->buf;
	r->cmd = el->el_state.thiscmd;
	r->ch = el->el_state.thisch;
}

/* cv_yank():
 *	Save yank/delete data for paste
 */
protected void
cv_yank(EditLine *el, const char *ptr, int size)
{
	c_kill_t *k = &el->el_chared.c_kill;

	memcpy(k->buf, ptr, size +0u);
	k->last = k->buf + size;
88 89 90 91 92 93 94 95 96 97 98
}


/* c_insert():
 *	Insert num characters
 */
protected void
c_insert(EditLine *el, int num)
{
	char *cp;

99 100 101 102
	if (el->el_line.lastchar + num >= el->el_line.limit) {
		if (!ch_enlargebufs(el, num +0u))
			return;		/* can't go past end of buffer */
	}
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122

	if (el->el_line.cursor < el->el_line.lastchar) {
		/* if I must move chars */
		for (cp = el->el_line.lastchar; cp >= el->el_line.cursor; cp--)
			cp[num] = *cp;
	}
	el->el_line.lastchar += num;
}


/* c_delafter():
 *	Delete num characters after the cursor
 */
protected void
c_delafter(EditLine *el, int num)
{

	if (el->el_line.cursor + num > el->el_line.lastchar)
		num = el->el_line.lastchar - el->el_line.cursor;

123 124 125 126 127
	if (el->el_map.current != el->el_map.emacs) {
		cv_undo(el);
		cv_yank(el, el->el_line.cursor, num);
	}

128 129 130 131 132 133 134 135 136 137 138
	if (num > 0) {
		char *cp;

		for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
			*cp = cp[num];

		el->el_line.lastchar -= num;
	}
}


139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
/* c_delafter1():
 *	Delete the character after the cursor, do not yank
 */
protected void
c_delafter1(EditLine *el)
{
	char *cp;

	for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
		*cp = cp[1];

	el->el_line.lastchar--;
}


154 155 156 157 158 159 160 161 162 163
/* c_delbefore():
 *	Delete num characters before the cursor
 */
protected void
c_delbefore(EditLine *el, int num)
{

	if (el->el_line.cursor - num < el->el_line.buffer)
		num = el->el_line.cursor - el->el_line.buffer;

164 165 166 167 168
	if (el->el_map.current != el->el_map.emacs) {
		cv_undo(el);
		cv_yank(el, el->el_line.cursor - num, num);
	}

169 170 171 172 173 174 175 176 177 178 179 180 181
	if (num > 0) {
		char *cp;

		for (cp = el->el_line.cursor - num;
		    cp <= el->el_line.lastchar;
		    cp++)
			*cp = cp[num];

		el->el_line.lastchar -= num;
	}
}


182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
/* c_delbefore1():
 *	Delete the character before the cursor, do not yank
 */
protected void
c_delbefore1(EditLine *el)
{
	char *cp;

	for (cp = el->el_line.cursor - 1; cp <= el->el_line.lastchar; cp++)
		*cp = cp[1];

	el->el_line.lastchar--;
}


197 198 199 200 201 202
/* ce__isword():
 *	Return if p is part of a word according to emacs
 */
protected int
ce__isword(int p)
{
203
	return (isalnum(p) || strchr("*?_-.[]~=", p) != NULL);
204 205 206 207 208 209 210 211
}


/* cv__isword():
 *	Return if p is part of a word according to vi
 */
protected int
cv__isword(int p)
212 213 214 215 216 217 218 219 220 221 222 223 224 225
{
	if (isalnum(p) || p == '_')
		return 1;
	if (isgraph(p))
		return 2;
	return 0;
}


/* cv__isWord():
 *	Return if p is part of a big word according to vi
 */
protected int
cv__isWord(int p)
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
{
	return (!isspace(p));
}


/* c__prev_word():
 *	Find the previous word
 */
protected char *
c__prev_word(char *p, char *low, int n, int (*wtest)(int))
{
	p--;

	while (n--) {
		while ((p >= low) && !(*wtest)((unsigned char) *p))
			p--;
		while ((p >= low) && (*wtest)((unsigned char) *p))
			p--;
	}

	/* cp now points to one character before the word */
	p++;
	if (p < low)
		p = low;
	/* cp now points where we want it */
	return (p);
}


/* c__next_word():
 *	Find the next word
 */
protected char *
c__next_word(char *p, char *high, int n, int (*wtest)(int))
{
	while (n--) {
		while ((p < high) && !(*wtest)((unsigned char) *p))
			p++;
		while ((p < high) && (*wtest)((unsigned char) *p))
			p++;
	}
	if (p > high)
		p = high;
	/* p now points where we want it */
	return (p);
}

/* cv_next_word():
 *	Find the next word vi style
 */
protected char *
cv_next_word(EditLine *el, char *p, char *high, int n, int (*wtest)(int))
{
	int test;

	while (n--) {
		test = (*wtest)((unsigned char) *p);
		while ((p < high) && (*wtest)((unsigned char) *p) == test)
			p++;
		/*
		 * vi historically deletes with cw only the word preserving the
		 * trailing whitespace! This is not what 'w' does..
		 */
289
		if (n || el->el_chared.c_vcmd.action != (DELETE|INSERT))
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
			while ((p < high) && isspace((unsigned char) *p))
				p++;
	}

	/* p now points where we want it */
	if (p > high)
		return (high);
	else
		return (p);
}


/* cv_prev_word():
 *	Find the previous word vi style
 */
protected char *
306
cv_prev_word(char *p, char *low, int n, int (*wtest)(int))
307 308 309
{
	int test;

310
	p--;
311
	while (n--) {
312 313
		while ((p > low) && isspace((unsigned char) *p))
			p--;
314 315 316 317
		test = (*wtest)((unsigned char) *p);
		while ((p >= low) && (*wtest)((unsigned char) *p) == test)
			p--;
	}
318
	p++;
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368

	/* p now points where we want it */
	if (p < low)
		return (low);
	else
		return (p);
}


#ifdef notdef
/* c__number():
 *	Ignore character p points to, return number appearing after that.
 * 	A '$' by itself means a big number; "$-" is for negative; '^' means 1.
 * 	Return p pointing to last char used.
 */
protected char *
c__number(
    char *p,	/* character position */
    int *num,	/* Return value	*/
    int dval)	/* dval is the number to subtract from like $-3 */
{
	int i;
	int sign = 1;

	if (*++p == '^') {
		*num = 1;
		return (p);
	}
	if (*p == '$') {
		if (*++p != '-') {
			*num = 0x7fffffff;	/* Handle $ */
			return (--p);
		}
		sign = -1;			/* Handle $- */
		++p;
	}
	for (i = 0; isdigit((unsigned char) *p); i = 10 * i + *p++ - '0')
		continue;
	*num = (sign < 0 ? dval - i : i);
	return (--p);
}
#endif

/* cv_delfini():
 *	Finish vi delete action
 */
protected void
cv_delfini(EditLine *el)
{
	int size;
369
	int action = el->el_chared.c_vcmd.action;
370

371
	if (action & INSERT)
372 373 374
		el->el_map.current = el->el_map.key;

	if (el->el_chared.c_vcmd.pos == 0)
375
		/* sanity */
376 377
		return;

378 379
	size = el->el_line.cursor - el->el_chared.c_vcmd.pos;
	if (size == 0)
380
		size = 1;
381 382 383 384 385 386 387 388 389 390 391 392 393 394
	el->el_line.cursor = el->el_chared.c_vcmd.pos;
	if (action & YANK) {
		if (size > 0)
			cv_yank(el, el->el_line.cursor, size);
		else
			cv_yank(el, el->el_line.cursor + size, -size);
	} else {
		if (size > 0) {
			c_delafter(el, size);
			re_refresh_cursor(el);
		} else  {
			c_delbefore(el, -size);
			el->el_line.cursor += size;
		}
395
	}
396
	el->el_chared.c_vcmd.action = NOP;
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
}


#ifdef notdef
/* ce__endword():
 *	Go to the end of this word according to emacs
 */
protected char *
ce__endword(char *p, char *high, int n)
{
	p++;

	while (n--) {
		while ((p < high) && isspace((unsigned char) *p))
			p++;
		while ((p < high) && !isspace((unsigned char) *p))
			p++;
	}

	p--;
	return (p);
}
#endif


/* cv__endword():
 *	Go to the end of this word according to vi
 */
protected char *
426
cv__endword(char *p, char *high, int n, int (*wtest)(int))
427
{
428 429
	int test;

430 431 432 433 434 435
	p++;

	while (n--) {
		while ((p < high) && isspace((unsigned char) *p))
			p++;

436 437 438
		test = (*wtest)((unsigned char) *p);
		while ((p < high) && (*wtest)((unsigned char) *p) == test)
			p++;
439 440 441 442 443 444 445 446 447 448 449
	}
	p--;
	return (p);
}

/* ch_init():
 *	Initialize the character editor
 */
protected int
ch_init(EditLine *el)
{
450 451
	c_macro_t *ma = &el->el_chared.c_macro;

452 453 454 455 456 457 458
	el->el_line.buffer		= (char *) el_malloc(EL_BUFSIZ);
	if (el->el_line.buffer == NULL)
		return (-1);

	(void) memset(el->el_line.buffer, 0, EL_BUFSIZ);
	el->el_line.cursor		= el->el_line.buffer;
	el->el_line.lastchar		= el->el_line.buffer;
459
	el->el_line.limit		= &el->el_line.buffer[EL_BUFSIZ - EL_LEAVE];
460 461 462 463 464

	el->el_chared.c_undo.buf	= (char *) el_malloc(EL_BUFSIZ);
	if (el->el_chared.c_undo.buf == NULL)
		return (-1);
	(void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ);
465 466 467 468 469 470 471 472
	el->el_chared.c_undo.len	= -1;
	el->el_chared.c_undo.cursor	= 0;
	el->el_chared.c_redo.buf	= (char *) el_malloc(EL_BUFSIZ);
	if (el->el_chared.c_redo.buf == NULL)
		return (-1);
	el->el_chared.c_redo.pos	= el->el_chared.c_redo.buf;
	el->el_chared.c_redo.lim	= el->el_chared.c_redo.buf + EL_BUFSIZ;
	el->el_chared.c_redo.cmd	= ED_UNASSIGNED;
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491

	el->el_chared.c_vcmd.action	= NOP;
	el->el_chared.c_vcmd.pos	= el->el_line.buffer;

	el->el_chared.c_kill.buf	= (char *) el_malloc(EL_BUFSIZ);
	if (el->el_chared.c_kill.buf == NULL)
		return (-1);
	(void) memset(el->el_chared.c_kill.buf, 0, EL_BUFSIZ);
	el->el_chared.c_kill.mark	= el->el_line.buffer;
	el->el_chared.c_kill.last	= el->el_chared.c_kill.buf;

	el->el_map.current		= el->el_map.key;

	el->el_state.inputmode		= MODE_INSERT; /* XXX: save a default */
	el->el_state.doingarg		= 0;
	el->el_state.metanext		= 0;
	el->el_state.argument		= 1;
	el->el_state.lastcmd		= ED_UNASSIGNED;

492 493 494 495
	ma->level	= -1;
	ma->offset	= 0;
	ma->macro	= (char **) el_malloc(EL_MAXMACRO * sizeof(char *));
	if (ma->macro == NULL)
496 497 498 499 500 501 502 503
		return (-1);
	return (0);
}

/* ch_reset():
 *	Reset the character editor
 */
protected void
504
ch_reset(EditLine *el, int mclear)
505 506 507 508
{
	el->el_line.cursor		= el->el_line.buffer;
	el->el_line.lastchar		= el->el_line.buffer;

509 510
	el->el_chared.c_undo.len	= -1;
	el->el_chared.c_undo.cursor	= 0;
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525

	el->el_chared.c_vcmd.action	= NOP;
	el->el_chared.c_vcmd.pos	= el->el_line.buffer;

	el->el_chared.c_kill.mark	= el->el_line.buffer;

	el->el_map.current		= el->el_map.key;

	el->el_state.inputmode		= MODE_INSERT; /* XXX: save a default */
	el->el_state.doingarg		= 0;
	el->el_state.metanext		= 0;
	el->el_state.argument		= 1;
	el->el_state.lastcmd		= ED_UNASSIGNED;

	el->el_history.eventno		= 0;
526 527 528 529 530 531 532 533 534 535 536 537

	if (mclear)
		ch__clearmacro(el);
}

private void
ch__clearmacro(el)
	EditLine *el;
{
	c_macro_t *ma = &el->el_chared.c_macro;
	while (ma->level >= 0)
		el_free((ptr_t)ma->macro[ma->level--]);
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
}

/* ch_enlargebufs():
 *	Enlarge line buffer to be able to hold twice as much characters.
 *	Returns 1 if successful, 0 if not.
 */
protected int
ch_enlargebufs(el, addlen)
	EditLine *el;
	size_t addlen;
{
	size_t sz, newsz;
	char *newbuffer, *oldbuf, *oldkbuf;

	sz = el->el_line.limit - el->el_line.buffer + EL_LEAVE;
	newsz = sz * 2;
	/*
	 * If newly required length is longer than current buffer, we need
	 * to make the buffer big enough to hold both old and new stuff.
	 */
	if (addlen > sz) {
		while(newsz - sz < addlen)
			newsz *= 2;
	}

	/*
	 * Reallocate line buffer.
	 */
	newbuffer = el_realloc(el->el_line.buffer, newsz);
	if (!newbuffer)
		return 0;

	/* zero the newly added memory, leave old data in */
	(void) memset(&newbuffer[sz], 0, newsz - sz);
	    
	oldbuf = el->el_line.buffer;

	el->el_line.buffer = newbuffer;
	el->el_line.cursor = newbuffer + (el->el_line.cursor - oldbuf);
	el->el_line.lastchar = newbuffer + (el->el_line.lastchar - oldbuf);
578 579
	/* don't set new size until all buffers are enlarged */
	el->el_line.limit  = &newbuffer[sz - EL_LEAVE];
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608

	/*
	 * Reallocate kill buffer.
	 */
	newbuffer = el_realloc(el->el_chared.c_kill.buf, newsz);
	if (!newbuffer)
		return 0;

	/* zero the newly added memory, leave old data in */
	(void) memset(&newbuffer[sz], 0, newsz - sz);

	oldkbuf = el->el_chared.c_kill.buf;

	el->el_chared.c_kill.buf = newbuffer;
	el->el_chared.c_kill.last = newbuffer +
					(el->el_chared.c_kill.last - oldkbuf);
	el->el_chared.c_kill.mark = el->el_line.buffer +
					(el->el_chared.c_kill.mark - oldbuf);

	/*
	 * Reallocate undo buffer.
	 */
	newbuffer = el_realloc(el->el_chared.c_undo.buf, newsz);
	if (!newbuffer)
		return 0;

	/* zero the newly added memory, leave old data in */
	(void) memset(&newbuffer[sz], 0, newsz - sz);
	el->el_chared.c_undo.buf = newbuffer;
609 610 611 612 613 614 615 616 617

	newbuffer = el_realloc(el->el_chared.c_redo.buf, newsz);
	if (!newbuffer)
		return 0;
	el->el_chared.c_redo.pos = newbuffer +
			(el->el_chared.c_redo.pos - el->el_chared.c_redo.buf);
	el->el_chared.c_redo.lim = newbuffer +
			(el->el_chared.c_redo.lim - el->el_chared.c_redo.buf);
	el->el_chared.c_redo.buf = newbuffer;
618 619 620 621
	
	if (!hist_enlargebuf(el, sz, newsz))
		return 0;

622
	/* Safe to set enlarged buffer size */
623
	el->el_line.limit  = &el->el_line.buffer[newsz - EL_LEAVE];
624 625 626 627 628 629 630 631 632 633 634 635 636 637
	return 1;
}

/* ch_end():
 *	Free the data structures used by the editor
 */
protected void
ch_end(EditLine *el)
{
	el_free((ptr_t) el->el_line.buffer);
	el->el_line.buffer = NULL;
	el->el_line.limit = NULL;
	el_free((ptr_t) el->el_chared.c_undo.buf);
	el->el_chared.c_undo.buf = NULL;
638 639 640 641 642
	el_free((ptr_t) el->el_chared.c_redo.buf);
	el->el_chared.c_redo.buf = NULL;
	el->el_chared.c_redo.pos = NULL;
	el->el_chared.c_redo.lim = NULL;
	el->el_chared.c_redo.cmd = ED_UNASSIGNED;
643 644
	el_free((ptr_t) el->el_chared.c_kill.buf);
	el->el_chared.c_kill.buf = NULL;
645
	ch_reset(el, 1);
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694
	el_free((ptr_t) el->el_chared.c_macro.macro);
	el->el_chared.c_macro.macro = NULL;
}


/* el_insertstr():
 *	Insert string at cursorI
 */
public int
el_insertstr(EditLine *el, const char *s)
{
	size_t len;

	if ((len = strlen(s)) == 0)
		return (-1);
	if (el->el_line.lastchar + len >= el->el_line.limit) {
		if (!ch_enlargebufs(el, len))
			return (-1);
	}

	c_insert(el, (int)len);
	while (*s)
		*el->el_line.cursor++ = *s++;
	return (0);
}


/* el_deletestr():
 *	Delete num characters before the cursor
 */
public void
el_deletestr(EditLine *el, int n)
{
	if (n <= 0)
		return;

	if (el->el_line.cursor < &el->el_line.buffer[n])
		return;

	c_delbefore(el, n);		/* delete before dot */
	el->el_line.cursor -= n;
	if (el->el_line.cursor < el->el_line.buffer)
		el->el_line.cursor = el->el_line.buffer;
}

/* c_gets():
 *	Get a string
 */
protected int
695
c_gets(EditLine *el, char *buf, const char *prompt)
696 697
{
	char ch;
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
	int len;
	char *cp = el->el_line.buffer;

	if (prompt) {
		len = strlen(prompt);
		memcpy(cp, prompt, len + 0u);
		cp += len;
	}
	len = 0;

	for (;;) {
		el->el_line.cursor = cp;
		*cp = ' ';
		el->el_line.lastchar = cp + 1;
		re_refresh(el);

		if (el_getc(el, &ch) != 1) {
			ed_end_of_file(el, 0);
			len = -1;
			break;
		}
719 720

		switch (ch) {
721

722 723
		case 0010:	/* Delete and backspace */
		case 0177:
724 725 726
			if (len <= 0) {
				len = -1;
				break;
727
			}
728 729
			cp--;
			continue;
730 731 732 733

		case 0033:	/* ESC */
		case '\r':	/* Newline */
		case '\n':
734
			buf[len] = ch;
735 736 737
			break;

		default:
738
			if (len >= EL_BUFSIZ - 16)
739 740 741
				term_beep(el);
			else {
				buf[len++] = ch;
742
				*cp++ = ch;
743
			}
744
			continue;
745
		}
746
		break;
747
	}
748 749 750 751 752

	el->el_line.buffer[0] = '\0';
	el->el_line.lastchar = el->el_line.buffer;
	el->el_line.cursor = el->el_line.buffer;
	return len;
753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
}


/* c_hpos():
 *	Return the current horizontal position of the cursor
 */
protected int
c_hpos(EditLine *el)
{
	char *ptr;

	/*
	 * Find how many characters till the beginning of this line.
	 */
	if (el->el_line.cursor == el->el_line.buffer)
		return (0);
	else {
		for (ptr = el->el_line.cursor - 1;
		     ptr >= el->el_line.buffer && *ptr != '\n';
		     ptr--)
			continue;
		return (el->el_line.cursor - ptr - 1);
	}
}