mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 18:55:19 +00:00 
			
		
		
		
	
		
			
	
	
		
			489 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			489 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*	$NetBSD: emacs.c,v 1.10 2002/03/18 16:00:52 christos Exp $	*/ | ||
|  | 
 | ||
|  | /*-
 | ||
|  |  * 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. | ||
|  |  * 3. All advertising materials mentioning features or use of this software | ||
|  |  *    must display the following acknowledgement: | ||
|  |  *	This product includes software developed by the University of | ||
|  |  *	California, Berkeley and its contributors. | ||
|  |  * 4. Neither the name of the University nor the names of its contributors | ||
|  |  *    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. | ||
|  |  */ | ||
|  | 
 | ||
|  | #include "config.h"
 | ||
|  | #if !defined(lint) && !defined(SCCSID)
 | ||
|  | #if 0
 | ||
|  | static char sccsid[] = "@(#)emacs.c	8.1 (Berkeley) 6/4/93"; | ||
|  | #else
 | ||
|  | __RCSID("$NetBSD: emacs.c,v 1.10 2002/03/18 16:00:52 christos Exp $"); | ||
|  | #endif
 | ||
|  | #endif /* not lint && not SCCSID */
 | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * emacs.c: Emacs functions | ||
|  |  */ | ||
|  | #include "el.h"
 | ||
|  | 
 | ||
|  | /* em_delete_or_list():
 | ||
|  |  *	Delete character under cursor or list completions if at end of line | ||
|  |  *	[^D] | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | /*ARGSUSED*/ | ||
|  | em_delete_or_list(EditLine *el, int c) | ||
|  | { | ||
|  | 
 | ||
|  | 	if (el->el_line.cursor == el->el_line.lastchar) { | ||
|  | 					/* if I'm at the end */ | ||
|  | 		if (el->el_line.cursor == el->el_line.buffer) { | ||
|  | 					/* and the beginning */ | ||
|  | 			term_overwrite(el, STReof, 4);	/* then do a EOF */ | ||
|  | 			term__flush(); | ||
|  | 			return (CC_EOF); | ||
|  | 		} else { | ||
|  | 			/*
 | ||
|  | 			 * Here we could list completions, but it is an | ||
|  | 			 * error right now | ||
|  | 			 */ | ||
|  | 			term_beep(el); | ||
|  | 			return (CC_ERROR); | ||
|  | 		} | ||
|  | 	} else { | ||
|  | 		c_delafter(el, el->el_state.argument);	/* delete after dot */ | ||
|  | 		if (el->el_line.cursor > el->el_line.lastchar) | ||
|  | 			el->el_line.cursor = el->el_line.lastchar; | ||
|  | 				/* bounds check */ | ||
|  | 		return (CC_REFRESH); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* em_delete_next_word():
 | ||
|  |  *	Cut from cursor to end of current word | ||
|  |  *	[M-d] | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | /*ARGSUSED*/ | ||
|  | em_delete_next_word(EditLine *el, int c) | ||
|  | { | ||
|  | 	char *cp, *p, *kp; | ||
|  | 
 | ||
|  | 	if (el->el_line.cursor == el->el_line.lastchar) | ||
|  | 		return (CC_ERROR); | ||
|  | 
 | ||
|  | 	cp = c__next_word(el->el_line.cursor, el->el_line.lastchar, | ||
|  | 	    el->el_state.argument, ce__isword); | ||
|  | 
 | ||
|  | 	for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++) | ||
|  | 				/* save the text */ | ||
|  | 		*kp++ = *p; | ||
|  | 	el->el_chared.c_kill.last = kp; | ||
|  | 
 | ||
|  | 	c_delafter(el, cp - el->el_line.cursor);	/* delete after dot */ | ||
|  | 	if (el->el_line.cursor > el->el_line.lastchar) | ||
|  | 		el->el_line.cursor = el->el_line.lastchar; | ||
|  | 				/* bounds check */ | ||
|  | 	return (CC_REFRESH); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* em_yank():
 | ||
|  |  *	Paste cut buffer at cursor position | ||
|  |  *	[^Y] | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | /*ARGSUSED*/ | ||
|  | em_yank(EditLine *el, int c) | ||
|  | { | ||
|  | 	char *kp, *cp; | ||
|  | 
 | ||
|  | 	if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf) { | ||
|  | 		if (!ch_enlargebufs(el, 1)) | ||
|  | 			return (CC_ERROR); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (el->el_line.lastchar + | ||
|  | 	    (el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >= | ||
|  | 	    el->el_line.limit) | ||
|  | 		return (CC_ERROR); | ||
|  | 
 | ||
|  | 	el->el_chared.c_kill.mark = el->el_line.cursor; | ||
|  | 	cp = el->el_line.cursor; | ||
|  | 
 | ||
|  | 	/* open the space, */ | ||
|  | 	c_insert(el, el->el_chared.c_kill.last - el->el_chared.c_kill.buf); | ||
|  | 	/* copy the chars */ | ||
|  | 	for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++) | ||
|  | 		*cp++ = *kp; | ||
|  | 
 | ||
|  | 	/* if an arg, cursor at beginning else cursor at end */ | ||
|  | 	if (el->el_state.argument == 1) | ||
|  | 		el->el_line.cursor = cp; | ||
|  | 
 | ||
|  | 	return (CC_REFRESH); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* em_kill_line():
 | ||
|  |  *	Cut the entire line and save in cut buffer | ||
|  |  *	[^U] | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | /*ARGSUSED*/ | ||
|  | em_kill_line(EditLine *el, int c) | ||
|  | { | ||
|  | 	char *kp, *cp; | ||
|  | 
 | ||
|  | 	cp = el->el_line.buffer; | ||
|  | 	kp = el->el_chared.c_kill.buf; | ||
|  | 	while (cp < el->el_line.lastchar) | ||
|  | 		*kp++ = *cp++;	/* copy it */ | ||
|  | 	el->el_chared.c_kill.last = kp; | ||
|  | 				/* zap! -- delete all of it */ | ||
|  | 	el->el_line.lastchar = el->el_line.buffer; | ||
|  | 	el->el_line.cursor = el->el_line.buffer; | ||
|  | 	return (CC_REFRESH); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* em_kill_region():
 | ||
|  |  *	Cut area between mark and cursor and save in cut buffer | ||
|  |  *	[^W] | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | /*ARGSUSED*/ | ||
|  | em_kill_region(EditLine *el, int c) | ||
|  | { | ||
|  | 	char *kp, *cp; | ||
|  | 
 | ||
|  | 	if (!el->el_chared.c_kill.mark) | ||
|  | 		return (CC_ERROR); | ||
|  | 
 | ||
|  | 	if (el->el_chared.c_kill.mark > el->el_line.cursor) { | ||
|  | 		cp = el->el_line.cursor; | ||
|  | 		kp = el->el_chared.c_kill.buf; | ||
|  | 		while (cp < el->el_chared.c_kill.mark) | ||
|  | 			*kp++ = *cp++;	/* copy it */ | ||
|  | 		el->el_chared.c_kill.last = kp; | ||
|  | 		c_delafter(el, cp - el->el_line.cursor); | ||
|  | 	} else {		/* mark is before cursor */ | ||
|  | 		cp = el->el_chared.c_kill.mark; | ||
|  | 		kp = el->el_chared.c_kill.buf; | ||
|  | 		while (cp < el->el_line.cursor) | ||
|  | 			*kp++ = *cp++;	/* copy it */ | ||
|  | 		el->el_chared.c_kill.last = kp; | ||
|  | 		c_delbefore(el, cp - el->el_chared.c_kill.mark); | ||
|  | 		el->el_line.cursor = el->el_chared.c_kill.mark; | ||
|  | 	} | ||
|  | 	return (CC_REFRESH); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* em_copy_region():
 | ||
|  |  *	Copy area between mark and cursor to cut buffer | ||
|  |  *	[M-W] | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | /*ARGSUSED*/ | ||
|  | em_copy_region(EditLine *el, int c) | ||
|  | { | ||
|  | 	char *kp, *cp; | ||
|  | 
 | ||
|  | 	if (el->el_chared.c_kill.mark) | ||
|  | 		return (CC_ERROR); | ||
|  | 
 | ||
|  | 	if (el->el_chared.c_kill.mark > el->el_line.cursor) { | ||
|  | 		cp = el->el_line.cursor; | ||
|  | 		kp = el->el_chared.c_kill.buf; | ||
|  | 		while (cp < el->el_chared.c_kill.mark) | ||
|  | 			*kp++ = *cp++;	/* copy it */ | ||
|  | 		el->el_chared.c_kill.last = kp; | ||
|  | 	} else { | ||
|  | 		cp = el->el_chared.c_kill.mark; | ||
|  | 		kp = el->el_chared.c_kill.buf; | ||
|  | 		while (cp < el->el_line.cursor) | ||
|  | 			*kp++ = *cp++;	/* copy it */ | ||
|  | 		el->el_chared.c_kill.last = kp; | ||
|  | 	} | ||
|  | 	return (CC_NORM); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* em_gosmacs_traspose():
 | ||
|  |  *	Exchange the two characters before the cursor | ||
|  |  *	Gosling emacs transpose chars [^T] | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | em_gosmacs_traspose(EditLine *el, int c) | ||
|  | { | ||
|  | 
 | ||
|  | 	if (el->el_line.cursor > &el->el_line.buffer[1]) { | ||
|  | 		/* must have at least two chars entered */ | ||
|  | 		c = el->el_line.cursor[-2]; | ||
|  | 		el->el_line.cursor[-2] = el->el_line.cursor[-1]; | ||
|  | 		el->el_line.cursor[-1] = c; | ||
|  | 		return (CC_REFRESH); | ||
|  | 	} else | ||
|  | 		return (CC_ERROR); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* em_next_word():
 | ||
|  |  *	Move next to end of current word | ||
|  |  *	[M-f] | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | /*ARGSUSED*/ | ||
|  | em_next_word(EditLine *el, int c) | ||
|  | { | ||
|  | 	if (el->el_line.cursor == el->el_line.lastchar) | ||
|  | 		return (CC_ERROR); | ||
|  | 
 | ||
|  | 	el->el_line.cursor = c__next_word(el->el_line.cursor, | ||
|  | 	    el->el_line.lastchar, | ||
|  | 	    el->el_state.argument, | ||
|  | 	    ce__isword); | ||
|  | 
 | ||
|  | 	if (el->el_map.type == MAP_VI) | ||
|  | 		if (el->el_chared.c_vcmd.action & DELETE) { | ||
|  | 			cv_delfini(el); | ||
|  | 			return (CC_REFRESH); | ||
|  | 		} | ||
|  | 	return (CC_CURSOR); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* em_upper_case():
 | ||
|  |  *	Uppercase the characters from cursor to end of current word | ||
|  |  *	[M-u] | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | /*ARGSUSED*/ | ||
|  | em_upper_case(EditLine *el, int c) | ||
|  | { | ||
|  | 	char *cp, *ep; | ||
|  | 
 | ||
|  | 	ep = c__next_word(el->el_line.cursor, el->el_line.lastchar, | ||
|  | 	    el->el_state.argument, ce__isword); | ||
|  | 
 | ||
|  | 	for (cp = el->el_line.cursor; cp < ep; cp++) | ||
|  | 		if (islower((unsigned char) *cp)) | ||
|  | 			*cp = toupper(*cp); | ||
|  | 
 | ||
|  | 	el->el_line.cursor = ep; | ||
|  | 	if (el->el_line.cursor > el->el_line.lastchar) | ||
|  | 		el->el_line.cursor = el->el_line.lastchar; | ||
|  | 	return (CC_REFRESH); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* em_capitol_case():
 | ||
|  |  *	Capitalize the characters from cursor to end of current word | ||
|  |  *	[M-c] | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | /*ARGSUSED*/ | ||
|  | em_capitol_case(EditLine *el, int c) | ||
|  | { | ||
|  | 	char *cp, *ep; | ||
|  | 
 | ||
|  | 	ep = c__next_word(el->el_line.cursor, el->el_line.lastchar, | ||
|  | 	    el->el_state.argument, ce__isword); | ||
|  | 
 | ||
|  | 	for (cp = el->el_line.cursor; cp < ep; cp++) { | ||
|  | 		if (isalpha((unsigned char) *cp)) { | ||
|  | 			if (islower((unsigned char) *cp)) | ||
|  | 				*cp = toupper(*cp); | ||
|  | 			cp++; | ||
|  | 			break; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	for (; cp < ep; cp++) | ||
|  | 		if (isupper((unsigned char) *cp)) | ||
|  | 			*cp = tolower(*cp); | ||
|  | 
 | ||
|  | 	el->el_line.cursor = ep; | ||
|  | 	if (el->el_line.cursor > el->el_line.lastchar) | ||
|  | 		el->el_line.cursor = el->el_line.lastchar; | ||
|  | 	return (CC_REFRESH); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* em_lower_case():
 | ||
|  |  *	Lowercase the characters from cursor to end of current word | ||
|  |  *	[M-l] | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | /*ARGSUSED*/ | ||
|  | em_lower_case(EditLine *el, int c) | ||
|  | { | ||
|  | 	char *cp, *ep; | ||
|  | 
 | ||
|  | 	ep = c__next_word(el->el_line.cursor, el->el_line.lastchar, | ||
|  | 	    el->el_state.argument, ce__isword); | ||
|  | 
 | ||
|  | 	for (cp = el->el_line.cursor; cp < ep; cp++) | ||
|  | 		if (isupper((unsigned char) *cp)) | ||
|  | 			*cp = tolower(*cp); | ||
|  | 
 | ||
|  | 	el->el_line.cursor = ep; | ||
|  | 	if (el->el_line.cursor > el->el_line.lastchar) | ||
|  | 		el->el_line.cursor = el->el_line.lastchar; | ||
|  | 	return (CC_REFRESH); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* em_set_mark():
 | ||
|  |  *	Set the mark at cursor | ||
|  |  *	[^@] | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | /*ARGSUSED*/ | ||
|  | em_set_mark(EditLine *el, int c) | ||
|  | { | ||
|  | 
 | ||
|  | 	el->el_chared.c_kill.mark = el->el_line.cursor; | ||
|  | 	return (CC_NORM); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* em_exchange_mark():
 | ||
|  |  *	Exchange the cursor and mark | ||
|  |  *	[^X^X] | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | /*ARGSUSED*/ | ||
|  | em_exchange_mark(EditLine *el, int c) | ||
|  | { | ||
|  | 	char *cp; | ||
|  | 
 | ||
|  | 	cp = el->el_line.cursor; | ||
|  | 	el->el_line.cursor = el->el_chared.c_kill.mark; | ||
|  | 	el->el_chared.c_kill.mark = cp; | ||
|  | 	return (CC_CURSOR); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* em_universal_argument():
 | ||
|  |  *	Universal argument (argument times 4) | ||
|  |  *	[^U] | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | /*ARGSUSED*/ | ||
|  | em_universal_argument(EditLine *el, int c) | ||
|  | {				/* multiply current argument by 4 */ | ||
|  | 
 | ||
|  | 	if (el->el_state.argument > 1000000) | ||
|  | 		return (CC_ERROR); | ||
|  | 	el->el_state.doingarg = 1; | ||
|  | 	el->el_state.argument *= 4; | ||
|  | 	return (CC_ARGHACK); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* em_meta_next():
 | ||
|  |  *	Add 8th bit to next character typed | ||
|  |  *	[<ESC>] | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | /*ARGSUSED*/ | ||
|  | em_meta_next(EditLine *el, int c) | ||
|  | { | ||
|  | 
 | ||
|  | 	el->el_state.metanext = 1; | ||
|  | 	return (CC_ARGHACK); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* em_toggle_overwrite():
 | ||
|  |  *	Switch from insert to overwrite mode or vice versa | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | /*ARGSUSED*/ | ||
|  | em_toggle_overwrite(EditLine *el, int c) | ||
|  | { | ||
|  | 
 | ||
|  | 	el->el_state.inputmode = (el->el_state.inputmode == MODE_INSERT) ? | ||
|  | 	    MODE_REPLACE : MODE_INSERT; | ||
|  | 	return (CC_NORM); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* em_copy_prev_word():
 | ||
|  |  *	Copy current word to cursor | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | /*ARGSUSED*/ | ||
|  | em_copy_prev_word(EditLine *el, int c) | ||
|  | { | ||
|  | 	char *cp, *oldc, *dp; | ||
|  | 
 | ||
|  | 	if (el->el_line.cursor == el->el_line.buffer) | ||
|  | 		return (CC_ERROR); | ||
|  | 
 | ||
|  | 	oldc = el->el_line.cursor; | ||
|  | 	/* does a bounds check */ | ||
|  | 	cp = c__prev_word(el->el_line.cursor, el->el_line.buffer, | ||
|  | 	    el->el_state.argument, ce__isword); | ||
|  | 
 | ||
|  | 	c_insert(el, oldc - cp); | ||
|  | 	for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++) | ||
|  | 		*dp++ = *cp; | ||
|  | 
 | ||
|  | 	el->el_line.cursor = dp;/* put cursor at end */ | ||
|  | 
 | ||
|  | 	return (CC_REFRESH); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* em_inc_search_next():
 | ||
|  |  *	Emacs incremental next search | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | /*ARGSUSED*/ | ||
|  | em_inc_search_next(EditLine *el, int c) | ||
|  | { | ||
|  | 
 | ||
|  | 	el->el_search.patlen = 0; | ||
|  | 	return (ce_inc_search(el, ED_SEARCH_NEXT_HISTORY)); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* em_inc_search_prev():
 | ||
|  |  *	Emacs incremental reverse search | ||
|  |  */ | ||
|  | protected el_action_t | ||
|  | /*ARGSUSED*/ | ||
|  | em_inc_search_prev(EditLine *el, int c) | ||
|  | { | ||
|  | 
 | ||
|  | 	el->el_search.patlen = 0; | ||
|  | 	return (ce_inc_search(el, ED_SEARCH_PREV_HISTORY)); | ||
|  | } |