Index: head/include/histedit.h =================================================================== --- head/include/histedit.h (revision 170510) +++ head/include/histedit.h (revision 170511) @@ -1,227 +1,230 @@ /*- * 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. 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. * * @(#)histedit.h 8.2 (Berkeley) 1/3/94 - * $NetBSD: histedit.h,v 1.28 2005/07/14 15:00:58 christos Exp $ + * $NetBSD: histedit.h,v 1.31 2006/12/15 22:13:33 christos Exp $ * $FreeBSD$ */ /* * histedit.h: Line editor and history interface. */ #ifndef _HISTEDIT_H_ #define _HISTEDIT_H_ #include #include __BEGIN_DECLS /* * ==== Editing ==== */ typedef struct editline EditLine; /* * For user-defined function interface */ typedef struct lineinfo { const char *buffer; const char *cursor; const char *lastchar; } LineInfo; /* * EditLine editor function return codes. * For user-defined function interface */ #define CC_NORM 0 #define CC_NEWLINE 1 #define CC_EOF 2 #define CC_ARGHACK 3 #define CC_REFRESH 4 #define CC_CURSOR 5 #define CC_ERROR 6 #define CC_FATAL 7 #define CC_REDISPLAY 8 #define CC_REFRESH_BEEP 9 /* * Initialization, cleanup, and resetting */ EditLine *el_init(const char *, FILE *, FILE *, FILE *); void el_end(EditLine *); void el_reset(EditLine *); /* * Get a line, a character or push a string back in the input queue */ const char *el_gets(EditLine *, int *); int el_getc(EditLine *, char *); void el_push(EditLine *, char *); /* * Beep! */ void el_beep(EditLine *); /* * High level function internals control * Parses argc, argv array and executes builtin editline commands */ int el_parse(EditLine *, int, const char **); /* * Low level editline access functions */ int el_set(EditLine *, int, ...); -int el_get(EditLine *, int, void *); +int el_get(EditLine *, int, ...); #if 0 unsigned char _el_fn_complete(EditLine *, int); #endif /* * el_set/el_get parameters */ #define EL_PROMPT 0 /* , el_pfunc_t); */ #define EL_TERMINAL 1 /* , const char *); */ #define EL_EDITOR 2 /* , const char *); */ #define EL_SIGNAL 3 /* , int); */ #define EL_BIND 4 /* , const char *, ..., NULL); */ #define EL_TELLTC 5 /* , const char *, ..., NULL); */ #define EL_SETTC 6 /* , const char *, ..., NULL); */ #define EL_ECHOTC 7 /* , const char *, ..., NULL); */ #define EL_SETTY 8 /* , const char *, ..., NULL); */ #define EL_ADDFN 9 /* , const char *, const char * */ /* , el_func_t); */ #define EL_HIST 10 /* , hist_fun_t, const char *); */ #define EL_EDITMODE 11 /* , int); */ #define EL_RPROMPT 12 /* , el_pfunc_t); */ #define EL_GETCFN 13 /* , el_rfunc_t); */ #define EL_CLIENTDATA 14 /* , void *); */ #define EL_UNBUFFERED 15 /* , int); */ #define EL_PREP_TERM 16 /* , int); */ +#define EL_GETTC 17 /* , const char *, ..., NULL); */ +#define EL_GETFP 18 /* , int, FILE **) */ +#define EL_SETFP 19 /* , int, FILE *) */ #define EL_BUILTIN_GETCFN (NULL) /* * Source named file or $PWD/.editrc or $HOME/.editrc */ int el_source(EditLine *, const char *); /* * Must be called when the terminal changes size; If EL_SIGNAL * is set this is done automatically otherwise it is the responsibility * of the application */ void el_resize(EditLine *); /* * Set user private data. */ void el_data_set __P((EditLine *, void *)); void * el_data_get __P((EditLine *)); /* * User-defined function interface. */ const LineInfo *el_line(EditLine *); int el_insertstr(EditLine *, const char *); void el_deletestr(EditLine *, int); /* * ==== History ==== */ typedef struct history History; typedef struct HistEvent { int num; const char *str; } HistEvent; /* * History access functions. */ History * history_init(void); void history_end(History *); int history(History *, HistEvent *, int, ...); #define H_FUNC 0 /* , UTSL */ #define H_SETSIZE 1 /* , const int); */ #define H_EVENT 1 /* , const int); */ #define H_GETSIZE 2 /* , void); */ #define H_FIRST 3 /* , void); */ #define H_LAST 4 /* , void); */ #define H_PREV 5 /* , void); */ #define H_NEXT 6 /* , void); */ #define H_CURR 8 /* , const int); */ #define H_SET 7 /* , int); */ #define H_ADD 9 /* , const char *); */ #define H_ENTER 10 /* , const char *); */ #define H_APPEND 11 /* , const char *); */ #define H_END 12 /* , void); */ #define H_NEXT_STR 13 /* , const char *); */ #define H_PREV_STR 14 /* , const char *); */ #define H_NEXT_EVENT 15 /* , const int); */ #define H_PREV_EVENT 16 /* , const int); */ #define H_LOAD 17 /* , const char *); */ #define H_SAVE 18 /* , const char *); */ #define H_CLEAR 19 /* , void); */ #define H_SETUNIQUE 20 /* , int); */ #define H_GETUNIQUE 21 /* , void); */ #define H_DEL 22 /* , int); */ /* * ==== Tokenization ==== */ typedef struct tokenizer Tokenizer; /* * String tokenization functions, using simplified sh(1) quoting rules */ Tokenizer *tok_init(const char *); void tok_end(Tokenizer *); void tok_reset(Tokenizer *); int tok_line(Tokenizer *, const LineInfo *, int *, const char ***, int *, int *); int tok_str(Tokenizer *, const char *, int *, const char ***); __END_DECLS #endif /* _HISTEDIT_H_ */ Index: head/lib/libedit/editline.3 =================================================================== --- head/lib/libedit/editline.3 (revision 170510) +++ head/lib/libedit/editline.3 (revision 170511) @@ -1,784 +1,832 @@ -.\" $NetBSD: editline.3,v 1.51 2006/08/21 12:45:30 christos Exp $ +.\" $NetBSD: editline.3,v 1.55 2007/01/12 16:31:13 christos Exp $ .\" .\" Copyright (c) 1997-2003 The NetBSD Foundation, Inc. .\" All rights reserved. .\" .\" This file was contributed to The NetBSD Foundation by Luke Mewburn. .\" .\" 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. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. .\" .\" $FreeBSD$ .\" -.Dd October 4, 2005 +.Dd January 12, 2007 .Os .Dt EDITLINE 3 .Sh NAME .Nm editline , .Nm el_init , .Nm el_end , .Nm el_reset , .Nm el_gets , .Nm el_getc , .Nm el_push , .Nm el_parse , .Nm el_set , .Nm el_get , .Nm el_source , .Nm el_resize , .Nm el_line , .Nm el_insertstr , .Nm el_deletestr , .Nm history_init , .Nm history_end , .Nm history , .Nm tok_init , .Nm tok_end , .Nm tok_reset , .Nm tok_line , .Nm tok_str .Nd line editor, history and tokenization functions .Sh LIBRARY .Lb libedit .Sh SYNOPSIS .In histedit.h .Ft EditLine * .Fn el_init "const char *prog" "FILE *fin" "FILE *fout" "FILE *ferr" .Ft void .Fn el_end "EditLine *e" .Ft void .Fn el_reset "EditLine *e" .Ft const char * .Fn el_gets "EditLine *e" "int *count" .Ft int .Fn el_getc "EditLine *e" "char *ch" .Ft void .Fn el_push "EditLine *e" "char *str" .Ft int .Fn el_parse "EditLine *e" "int argc" "const char *argv[]" .Ft int .Fn el_set "EditLine *e" "int op" "..." .Ft int -.Fn el_get "EditLine *e" "int op" "void *result" +.Fn el_get "EditLine *e" "int op" "..." .Ft int .Fn el_source "EditLine *e" "const char *file" .Ft void .Fn el_resize "EditLine *e" .Ft const LineInfo * .Fn el_line "EditLine *e" .Ft int .Fn el_insertstr "EditLine *e" "const char *str" .Ft void .Fn el_deletestr "EditLine *e" "int count" .Ft History * .Fn history_init .Ft void .Fn history_end "History *h" .Ft int .Fn history "History *h" "HistEvent *ev" "int op" "..." .Ft Tokenizer * .Fn tok_init "const char *IFS" .Ft void .Fn tok_end "Tokenizer *t" .Ft void .Fn tok_reset "Tokenizer *t" .Ft int .Fo tok_line .Fa "Tokenizer *t" "const LineInfo *li" "int *argc" "const char **argv[]" .Fa "int *cursorc" "int *cursoro" .Fc .Ft int .Fn tok_str "Tokenizer *t" "const char *str" "int *argc" "const char **argv[]" .Sh DESCRIPTION The .Nm library provides generic line editing, history and tokenization functions, similar to those found in .Xr sh 1 . .Pp These functions are available in the .Nm libedit library (which needs the .Nm libtermcap library). Programs should be linked with .Fl ledit ltermcap . .Sh LINE EDITING FUNCTIONS The line editing functions use a common data structure, .Fa EditLine , which is created by .Fn el_init and freed by .Fn el_end . .Pp The following functions are available: .Bl -tag -width 4n .It Fn el_init Initialise the line editor, and return a data structure to be used by all other line editing functions. .Fa prog is the name of the invoking program, used when reading the .Xr editrc 5 file to determine which settings to use. .Fa fin , .Fa fout and .Fa ferr are the input, output, and error streams (respectively) to use. In this documentation, references to .Dq the tty are actually to this input/output stream combination. .It Fn el_end Clean up and finish with .Fa e , assumed to have been created with .Fn el_init . .It Fn el_reset Reset the tty and the parser. This should be called after an error which may have upset the tty's state. .It Fn el_gets Read a line from the tty. .Fa count is modified to contain the number of characters read. Returns the line read if successful, or .Dv NULL if no characters were read or if an error occurred. .It Fn el_getc Read a character from the tty. .Fa ch is modified to contain the character read. Returns the number of characters read if successful, \-1 otherwise. .It Fn el_push Pushes .Fa str back onto the input stream. This is used by the macro expansion mechanism. Refer to the description of .Ic bind .Fl s in .Xr editrc 5 for more information. .It Fn el_parse Parses the .Fa argv array (which is .Fa argc elements in size) to execute builtin .Nm commands. If the command is prefixed with .Dq prog: then .Fn el_parse will only execute the command if .Dq prog matches the .Fa prog argument supplied to .Fn el_init . The return value is \-1 if the command is unknown, 0 if there was no error or .Dq prog did not match, or 1 if the command returned an error. Refer to .Xr editrc 5 for more information. .It Fn el_set Set .Nm parameters. .Fa op determines which parameter to set, and each operation has its own parameter list. .Pp The following values for .Fa op are supported, along with the required argument list: .Bl -tag -width 4n .It Dv EL_PROMPT , Fa "char *(*f)(EditLine *)" Define prompt printing function as .Fa f , which is to return a string that contains the prompt. .It Dv EL_RPROMPT , Fa "char *(*f)(EditLine *)" Define right side prompt printing function as .Fa f , which is to return a string that contains the prompt. .It Dv EL_TERMINAL , Fa "const char *type" Define terminal type of the tty to be .Fa type , or to .Ev TERM if .Fa type is .Dv NULL . .It Dv EL_EDITOR , Fa "const char *mode" Set editing mode to .Fa mode , which must be one of .Dq emacs or .Dq vi . .It Dv EL_SIGNAL , Fa "int flag" If .Fa flag is non-zero, .Nm will install its own signal handler for the following signals when reading command input: .Dv SIGCONT , .Dv SIGHUP , .Dv SIGINT , .Dv SIGQUIT , .Dv SIGSTOP , .Dv SIGTERM , .Dv SIGTSTP , and .Dv SIGWINCH . Otherwise, the current signal handlers will be used. .It Dv EL_BIND , Xo .Fa "const char *" , .Fa "..." , .Dv NULL .Xc Perform the .Ic bind builtin command. Refer to .Xr editrc 5 for more information. .It Dv EL_ECHOTC , Xo .Fa "const char *" , .Fa "..." , .Dv NULL .Xc Perform the .Ic echotc builtin command. Refer to .Xr editrc 5 for more information. .It Dv EL_SETTC , Xo .Fa "const char *" , .Fa "..." , .Dv NULL .Xc Perform the .Ic settc builtin command. Refer to .Xr editrc 5 for more information. .It Dv EL_SETTY , Xo .Fa "const char *" , .Fa "..." , .Dv NULL .Xc Perform the .Ic setty builtin command. Refer to .Xr editrc 5 for more information. .It Dv EL_TELLTC , Xo .Fa "const char *" , .Fa "..." , .Dv NULL .Xc Perform the .Ic telltc builtin command. Refer to .Xr editrc 5 for more information. .It Dv EL_ADDFN , Xo .Fa "const char *name" , .Fa "const char *help" , .Fa "unsigned char (*func)(EditLine *e, int ch)" .Xc Add a user defined function, .Fn func , referred to as .Fa name which is invoked when a key which is bound to .Fa name is entered. .Fa help is a description of .Fa name . At invocation time, .Fa ch is the key which caused the invocation. The return value of .Fn func should be one of: .Bl -tag -width "CC_REDISPLAY" .It Dv CC_NORM Add a normal character. .It Dv CC_NEWLINE End of line was entered. .It Dv CC_EOF EOF was entered. .It Dv CC_ARGHACK Expecting further command input as arguments, do nothing visually. .It Dv CC_REFRESH Refresh display. .It Dv CC_REFRESH_BEEP Refresh display, and beep. .It Dv CC_CURSOR Cursor moved, so update and perform .Dv CC_REFRESH . .It Dv CC_REDISPLAY Redisplay entire input line. This is useful if a key binding outputs extra information. .It Dv CC_ERROR An error occurred. Beep, and flush tty. .It Dv CC_FATAL Fatal error, reset tty to known state. .El .It Dv EL_HIST , Xo .Fa "History *(*func)(History *, int op, ...)" , .Fa "const char *ptr" .Xc Defines which history function to use, which is usually .Fn history . .Fa ptr should be the value returned by .Fn history_init . .It Dv EL_EDITMODE , Fa "int flag" If .Fa flag is non-zero, editing is enabled (the default). Note that this is only an indication, and does not affect the operation of .Nm . At this time, it is the caller's responsibility to check this (using .Fn el_get ) to determine if editing should be enabled or not. .It Dv EL_GETCFN , Fa "int (*f)(EditLine *, char *c)" Define the character reading function as .Fa f , which is to return the number of characters read and store them in .Fa c . This function is called internally by .Fn el_gets and .Fn el_getc . The builtin function can be set or restored with the special function name .Dv EL_BUILTIN_GETCFN . .It Dv EL_CLIENTDATA , Fa "void *data" Register .Fa data to be associated with this EditLine structure. It can be retrieved with the corresponding .Fn el_get call. +.It Dv EL_SETFP , Fa "int fd" , Fa "FILE *fp" +Set the current +.Nm editline +file pointer for +.Dq input +.Fa fd += +.Dv 0 , +.Dq output +.Fa fd += +.Dv 1 , +or +.Dq error +.Fa fd += +.Dv 2 +from +.Fa fp . .El .It Fn el_get Get .Nm parameters. .Fa op determines which parameter to retrieve into .Fa result . Returns 0 if successful, \-1 otherwise. .Pp The following values for .Fa op are supported, along with actual type of .Fa result : .Bl -tag -width 4n .It Dv EL_PROMPT , Fa "char *(*f)(EditLine *)" Return a pointer to the function that displays the prompt. .It Dv EL_RPROMPT , Fa "char *(*f)(EditLine *)" Return a pointer to the function that displays the rightside prompt. .It Dv EL_EDITOR , Fa "const char *" Return the name of the editor, which will be one of .Dq emacs or .Dq vi . +.It Dv EL_GETTC , Fa "const char *name" , Fa "void *value" +Return non-zero if +.Fa name +is a valid +.Xr termcap 5 +capability +and set +.Fa value +to the current value of that capability. .It Dv EL_SIGNAL , Fa "int *" Return non-zero if .Nm has installed private signal handlers (see .Fn el_get above). -.It Dv EL_EDITMODE, Fa "int *" +.It Dv EL_EDITMODE , Fa "int *" Return non-zero if editing is enabled. -.It Dv EL_GETCFN, Fa "int (**f)(EditLine *, char *)" +.It Dv EL_GETCFN , Fa "int (**f)(EditLine *, char *)" Return a pointer to the function that read characters, which is equal to .Dv EL_BUILTIN_GETCFN in the case of the default builtin function. .It Dv EL_CLIENTDATA , Fa "void **data" Retrieve .Fa data previously registered with the corresponding .Fn el_set call. -.It Dv EL_UNBUFFERED, Fa "int" +.It Dv EL_UNBUFFERED , Fa "int" Sets or clears unbuffered mode. In this mode, .Fn el_gets will return immediately after processing a single character. -.It Dv EL_PREP_TERM, Fa "int" +.It Dv EL_PREP_TERM , Fa "int" Sets or clears terminal editing mode. +.It Dv EL_GETFP , Fa "int fd", Fa "FILE **fp" +Return in +.Fa fp +the current +.Nm editline +file pointer for +.Dq input +.Fa fd += +.Dv 0 , +.Dq output +.Fa fd += +.Dv 1 , +or +.Dq error +.Fa fd += +.Dv 2 . .El .It Fn el_source Initialise .Nm by reading the contents of .Fa file . .Fn el_parse is called for each line in .Fa file . If .Fa file is .Dv NULL , try .Pa $PWD/.editrc then .Pa $HOME/.editrc . Refer to .Xr editrc 5 for details on the format of .Fa file . .It Fn el_resize Must be called if the terminal size changes. If .Dv EL_SIGNAL has been set with .Fn el_set , then this is done automatically. Otherwise, it is the responsibility of the application to call .Fn el_resize on the appropriate occasions. .It Fn el_line Return the editing information for the current line in a .Fa LineInfo structure, which is defined as follows: .Bd -literal typedef struct lineinfo { const char *buffer; /* address of buffer */ const char *cursor; /* address of cursor */ const char *lastchar; /* address of last character */ } LineInfo; .Ed .Pp .Fa buffer is not NUL terminated. This function may be called after .Fn el_gets to obtain the .Fa LineInfo structure pertaining to line returned by that function, and from within user defined functions added with .Dv EL_ADDFN . .It Fn el_insertstr Insert .Fa str into the line at the cursor. Returns \-1 if .Fa str is empty or will not fit, and 0 otherwise. .It Fn el_deletestr Delete -.Fa num +.Fa count characters before the cursor. .El .Sh HISTORY LIST FUNCTIONS The history functions use a common data structure, .Fa History , which is created by .Fn history_init and freed by .Fn history_end . .Pp The following functions are available: .Bl -tag -width 4n .It Fn history_init Initialise the history list, and return a data structure to be used by all other history list functions. .It Fn history_end Clean up and finish with .Fa h , assumed to have been created with .Fn history_init . .It Fn history Perform operation .Fa op on the history list, with optional arguments as needed by the operation. .Fa ev is changed accordingly to operation. The following values for .Fa op are supported, along with the required argument list: .Bl -tag -width 4n .It Dv H_SETSIZE , Fa "int size" Set size of history to .Fa size elements. .It Dv H_GETSIZE Get number of events currently in history. .It Dv H_END Cleans up and finishes with .Fa h , assumed to be created with .Fn history_init . .It Dv H_CLEAR Clear the history. .It Dv H_FUNC , Xo .Fa "void *ptr" , .Fa "history_gfun_t first" , .Fa "history_gfun_t next" , .Fa "history_gfun_t last" , .Fa "history_gfun_t prev" , .Fa "history_gfun_t curr" , .Fa "history_sfun_t set" , .Fa "history_vfun_t clear" , .Fa "history_efun_t enter" , .Fa "history_efun_t add" .Xc Define functions to perform various history operations. .Fa ptr is the argument given to a function when it is invoked. .It Dv H_FIRST Return the first element in the history. .It Dv H_LAST Return the last element in the history. .It Dv H_PREV Return the previous element in the history. .It Dv H_NEXT Return the next element in the history. .It Dv H_CURR Return the current element in the history. .It Dv H_SET Set the cursor to point to the requested element. .It Dv H_ADD , Fa "const char *str" Append .Fa str to the current element of the history, or perform the .Dv H_ENTER operation with argument .Fa str if there is no current element. .It Dv H_APPEND , Fa "const char *str" Append .Fa str to the last new element of the history. .It Dv H_ENTER , Fa "const char *str" Add .Fa str as a new element to the history, and, if necessary, removing the oldest entry to keep the list to the created size. If .Dv H_SETUNIQUE was has been called with a non-zero arguments, the element will not be entered into the history if its contents match the ones of the current history element. If the element is entered .Fn history returns 1, if it is ignored as a duplicate returns 0. Finally .Fn history returns \-1 if an error occurred. .It Dv H_PREV_STR , Fa "const char *str" Return the closest previous event that starts with .Fa str . .It Dv H_NEXT_STR , Fa "const char *str" Return the closest next event that starts with .Fa str . .It Dv H_PREV_EVENT , Fa "int e" Return the previous event numbered .Fa e . .It Dv H_NEXT_EVENT , Fa "int e" Return the next event numbered .Fa e . .It Dv H_LOAD , Fa "const char *file" Load the history list stored in .Fa file . .It Dv H_SAVE , Fa "const char *file" Save the history list to .Fa file . .It Dv H_SETUNIQUE , Fa "int unique" Set flag that adjacent identical event strings should not be entered into the history. .It Dv H_GETUNIQUE Retrieve the current setting if adjacent identical elements should be entered into the history. -.It Dv H_DEL , Fa "int num" +.It Dv H_DEL , Fa "int e" Delete the event numbered .Fa e . This function is only provided for .Xr readline 3 compatibility. The caller is responsible for free'ing the string in the returned .Fa HistEvent . .El .Pp The .Fn history function returns \*[Ge] 0 if the operation .Fa op succeeds. Otherwise, \-1 is returned and .Fa ev is updated to contain more details about the error. .El .Sh TOKENIZATION FUNCTIONS The tokenization functions use a common data structure, .Fa Tokenizer , which is created by .Fn tok_init and freed by .Fn tok_end . .Pp The following functions are available: .Bl -tag -width 4n .It Fn tok_init Initialise the tokenizer, and return a data structure to be used by all other tokenizer functions. .Fa IFS contains the Input Field Separators, which defaults to .Aq space , .Aq tab , and .Aq newline if .Dv NULL . .It Fn tok_end Clean up and finish with .Fa t , assumed to have been created with .Fn tok_init . .It Fn tok_reset Reset the tokenizer state. Use after a line has been successfully tokenized by .Fn tok_line or .Fn tok_str and before a new line is to be tokenized. .It Fn tok_line Tokenize .Fa li , If successful, modify: .Fa argv to contain the words, .Fa argc to contain the number of words, .Fa cursorc (if not .Dv NULL ) to contain the index of the word containing the cursor, and .Fa cursoro (if not .Dv NULL ) to contain the offset within .Fa argv[cursorc] of the cursor. .Pp Returns 0 if successful, \-1 for an internal error, 1 for an unmatched single quote, 2 for an unmatched double quote, and 3 for a backslash quoted .Aq newline . A positive exit code indicates that another line should be read and tokenization attempted again. .It Fn tok_str A simpler form of .Fn tok_line ; .Fa str is a NUL terminated string to tokenize. .El .\"XXX.Sh EXAMPLES .\"XXX: provide some examples .Sh SEE ALSO .Xr sh 1 , .Xr signal 3 , .Xr termcap 3 , -.Xr editrc 5 +.Xr editrc 5 , +.Xr termcap 5 .Sh HISTORY The .Nm library first appeared in .Bx 4.4 . .Dv CC_REDISPLAY appeared in .Nx 1.3 . .Dv CC_REFRESH_BEEP and .Dv EL_EDITMODE appeared in .Nx 1.4 . .Dv EL_RPROMPT appeared in .Nx 1.5 . .Sh AUTHORS .An -nosplit The .Nm library was written by .An Christos Zoulas . .An Luke Mewburn wrote this manual and implemented .Dv CC_REDISPLAY , .Dv CC_REFRESH_BEEP , .Dv EL_EDITMODE , and .Dv EL_RPROMPT . .Sh BUGS At this time, it is the responsibility of the caller to check the result of the .Dv EL_EDITMODE operation of .Fn el_get (after an .Fn el_source or .Fn el_parse ) to determine if .Nm should be used for further input. I.e., .Dv EL_EDITMODE is purely an indication of the result of the most recent .Xr editrc 5 .Ic edit command. Index: head/lib/libedit/el.c =================================================================== --- head/lib/libedit/el.c (revision 170510) +++ head/lib/libedit/el.c (revision 170511) @@ -1,562 +1,600 @@ /*- * 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. 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. * - * $NetBSD: el.c,v 1.41 2005/08/19 04:21:47 christos Exp $ + * $NetBSD: el.c,v 1.44 2006/12/15 22:13:33 christos Exp $ */ #if !defined(lint) && !defined(SCCSID) static char sccsid[] = "@(#)el.c 8.2 (Berkeley) 1/3/94"; #endif /* not lint && not SCCSID */ #include __FBSDID("$FreeBSD$"); /* * el.c: EditLine interface functions */ #include "sys.h" #include #include #include #include #include #include "el.h" #define HAVE_ISSETUGID /* el_init(): * Initialize editline and set default parameters. */ public EditLine * el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr) { EditLine *el = (EditLine *) el_malloc(sizeof(EditLine)); if (el == NULL) return (NULL); memset(el, 0, sizeof(EditLine)); - el->el_infd = fileno(fin); + el->el_infile = fin; el->el_outfile = fout; el->el_errfile = ferr; + + el->el_infd = fileno(fin); + if ((el->el_prog = el_strdup(prog)) == NULL) { el_free(el); return NULL; } /* * Initialize all the modules. Order is important!!! */ el->el_flags = 0; if (term_init(el) == -1) { el_free(el->el_prog); el_free(el); return NULL; } (void) key_init(el); (void) map_init(el); if (tty_init(el) == -1) el->el_flags |= NO_TTY; (void) ch_init(el); (void) search_init(el); (void) hist_init(el); (void) prompt_init(el); (void) sig_init(el); (void) read_init(el); return (el); } /* el_end(): * Clean up. */ public void el_end(EditLine *el) { if (el == NULL) return; el_reset(el); term_end(el); key_end(el); map_end(el); tty_end(el); ch_end(el); search_end(el); hist_end(el); prompt_end(el); sig_end(el); el_free((ptr_t) el->el_prog); el_free((ptr_t) el); } /* el_reset(): * Reset the tty and the parser */ public void el_reset(EditLine *el) { tty_cookedmode(el); ch_reset(el, 0); /* XXX: Do we want that? */ } /* el_set(): * set the editline parameters */ public int el_set(EditLine *el, int op, ...) { - va_list va; + va_list ap; int rv = 0; if (el == NULL) return (-1); - va_start(va, op); + va_start(ap, op); switch (op) { case EL_PROMPT: case EL_RPROMPT: - rv = prompt_set(el, va_arg(va, el_pfunc_t), op); + rv = prompt_set(el, va_arg(ap, el_pfunc_t), op); break; case EL_TERMINAL: - rv = term_set(el, va_arg(va, char *)); + rv = term_set(el, va_arg(ap, char *)); break; case EL_EDITOR: - rv = map_set_editor(el, va_arg(va, char *)); + rv = map_set_editor(el, va_arg(ap, char *)); break; case EL_SIGNAL: - if (va_arg(va, int)) + if (va_arg(ap, int)) el->el_flags |= HANDLE_SIGNALS; else el->el_flags &= ~HANDLE_SIGNALS; break; case EL_BIND: case EL_TELLTC: case EL_SETTC: + case EL_GETTC: case EL_ECHOTC: case EL_SETTY: { const char *argv[20]; int i; for (i = 1; i < 20; i++) - if ((argv[i] = va_arg(va, char *)) == NULL) + if ((argv[i] = va_arg(ap, char *)) == NULL) break; switch (op) { case EL_BIND: argv[0] = "bind"; rv = map_bind(el, i, argv); break; case EL_TELLTC: argv[0] = "telltc"; rv = term_telltc(el, i, argv); break; case EL_SETTC: argv[0] = "settc"; rv = term_settc(el, i, argv); break; case EL_ECHOTC: argv[0] = "echotc"; rv = term_echotc(el, i, argv); break; case EL_SETTY: argv[0] = "setty"; rv = tty_stty(el, i, argv); break; default: rv = -1; EL_ABORT((el->el_errfile, "Bad op %d\n", op)); break; } break; } case EL_ADDFN: { - char *name = va_arg(va, char *); - char *help = va_arg(va, char *); - el_func_t func = va_arg(va, el_func_t); + char *name = va_arg(ap, char *); + char *help = va_arg(ap, char *); + el_func_t func = va_arg(ap, el_func_t); rv = map_addfunc(el, name, help, func); break; } case EL_HIST: { - hist_fun_t func = va_arg(va, hist_fun_t); - ptr_t ptr = va_arg(va, char *); + hist_fun_t func = va_arg(ap, hist_fun_t); + ptr_t ptr = va_arg(ap, char *); rv = hist_set(el, func, ptr); break; } case EL_EDITMODE: - if (va_arg(va, int)) + if (va_arg(ap, int)) el->el_flags &= ~EDIT_DISABLED; else el->el_flags |= EDIT_DISABLED; rv = 0; break; case EL_GETCFN: { - el_rfunc_t rc = va_arg(va, el_rfunc_t); + el_rfunc_t rc = va_arg(ap, el_rfunc_t); rv = el_read_setfn(el, rc); break; } case EL_CLIENTDATA: - el->el_data = va_arg(va, void *); + el->el_data = va_arg(ap, void *); break; case EL_UNBUFFERED: - rv = va_arg(va, int); + rv = va_arg(ap, int); if (rv && !(el->el_flags & UNBUFFERED)) { el->el_flags |= UNBUFFERED; read_prepare(el); } else if (!rv && (el->el_flags & UNBUFFERED)) { el->el_flags &= ~UNBUFFERED; read_finish(el); } rv = 0; break; case EL_PREP_TERM: - rv = va_arg(va, int); + rv = va_arg(ap, int); if (rv) (void) tty_rawmode(el); else (void) tty_cookedmode(el); rv = 0; break; + case EL_SETFP: + { + FILE *fp; + int what; + + what = va_arg(ap, int); + fp = va_arg(ap, FILE *); + + rv = 0; + switch (what) { + case 0: + el->el_infile = fp; + el->el_infd = fileno(fp); + break; + case 1: + el->el_outfile = fp; + break; + case 2: + el->el_errfile = fp; + break; + default: + rv = -1; + break; + } + break; + } + default: rv = -1; break; } - va_end(va); + va_end(ap); return (rv); } /* el_get(): * retrieve the editline parameters */ public int -el_get(EditLine *el, int op, void *ret) +el_get(EditLine *el, int op, ...) { + va_list ap; int rv; - if (el == NULL || ret == NULL) - return (-1); + if (el == NULL) + return -1; + + va_start(ap, op); + switch (op) { case EL_PROMPT: case EL_RPROMPT: - rv = prompt_get(el, (el_pfunc_t *) ret, op); + rv = prompt_get(el, va_arg(ap, el_pfunc_t *), op); break; case EL_EDITOR: - rv = map_get_editor(el, (const char **)ret); + rv = map_get_editor(el, va_arg(ap, const char **)); break; case EL_SIGNAL: - *((int *) ret) = (el->el_flags & HANDLE_SIGNALS); + *va_arg(ap, int *) = (el->el_flags & HANDLE_SIGNALS); rv = 0; break; case EL_EDITMODE: - *((int *) ret) = (!(el->el_flags & EDIT_DISABLED)); + *va_arg(ap, int *) = !(el->el_flags & EDIT_DISABLED); rv = 0; break; case EL_TERMINAL: - term_get(el, (const char **)ret); + term_get(el, va_arg(ap, const char **)); rv = 0; break; -#if 0 /* XXX */ - case EL_BIND: - case EL_TELLTC: - case EL_SETTC: - case EL_ECHOTC: - case EL_SETTY: + case EL_GETTC: { - const char *argv[20]; + static char name[] = "gettc"; + char *argv[20]; int i; for (i = 1; i < sizeof(argv) / sizeof(argv[0]); i++) - if ((argv[i] = va_arg(va, char *)) == NULL) + if ((argv[i] = va_arg(ap, char *)) == NULL) break; switch (op) { - case EL_BIND: - argv[0] = "bind"; - rv = map_bind(el, i, argv); + case EL_GETTC: + argv[0] = name; + rv = term_gettc(el, i, argv); break; - case EL_TELLTC: - argv[0] = "telltc"; - rv = term_telltc(el, i, argv); - break; - - case EL_SETTC: - argv[0] = "settc"; - rv = term_settc(el, i, argv); - break; - - case EL_ECHOTC: - argv[0] = "echotc"; - rv = term_echotc(el, i, argv); - break; - - case EL_SETTY: - argv[0] = "setty"; - rv = tty_stty(el, i, argv); - break; - default: rv = -1; - EL_ABORT((el->errfile, "Bad op %d\n", op)); + EL_ABORT((el->el_errfile, "Bad op %d\n", op)); break; } break; } +#if 0 /* XXX */ case EL_ADDFN: { - char *name = va_arg(va, char *); - char *help = va_arg(va, char *); - el_func_t func = va_arg(va, el_func_t); + char *name = va_arg(ap, char *); + char *help = va_arg(ap, char *); + el_func_t func = va_arg(ap, el_func_t); rv = map_addfunc(el, name, help, func); break; } case EL_HIST: { - hist_fun_t func = va_arg(va, hist_fun_t); - ptr_t ptr = va_arg(va, char *); + hist_fun_t func = va_arg(ap, hist_fun_t); + ptr_t ptr = va_arg(ap, char *); rv = hist_set(el, func, ptr); } break; #endif /* XXX */ case EL_GETCFN: - *((el_rfunc_t *)ret) = el_read_getfn(el); + *va_arg(ap, el_rfunc_t *) = el_read_getfn(el); rv = 0; break; case EL_CLIENTDATA: - *((void **)ret) = el->el_data; + *va_arg(ap, void **) = el->el_data; rv = 0; break; case EL_UNBUFFERED: - *((int *) ret) = (!(el->el_flags & UNBUFFERED)); + *va_arg(ap, int *) = (!(el->el_flags & UNBUFFERED)); rv = 0; break; + case EL_GETFP: + { + int what; + FILE **fpp; + + what = va_arg(ap, int); + fpp = va_arg(ap, FILE **); + rv = 0; + switch (what) { + case 0: + *fpp = el->el_infile; + break; + case 1: + *fpp = el->el_outfile; + break; + case 2: + *fpp = el->el_errfile; + break; + default: + rv = -1; + break; + } + break; + } default: rv = -1; + break; } + va_end(ap); return (rv); } /* el_data_get(): * Set user private data. */ public void el_data_set (el, data) EditLine *el; void *data; { el->el_data = data; return; } /* el_data_get(): * Return user private data. */ public void * el_data_get (el) EditLine *el; { if (el->el_data) return (el->el_data); return (NULL); } /* el_line(): * Return editing info */ public const LineInfo * el_line(EditLine *el) { return (const LineInfo *) (void *) &el->el_line; } /* el_source(): * Source a file */ public int el_source(EditLine *el, const char *fname) { FILE *fp; size_t len; char *ptr; fp = NULL; if (fname == NULL) { #ifdef HAVE_ISSETUGID static const char elpath[] = "/.editrc"; char path[MAXPATHLEN]; if (issetugid()) return (-1); if ((ptr = getenv("HOME")) == NULL) return (-1); if (strlcpy(path, ptr, sizeof(path)) >= sizeof(path)) return (-1); if (strlcat(path, elpath, sizeof(path)) >= sizeof(path)) return (-1); fname = path; #else /* * If issetugid() is missing, always return an error, in order * to keep from inadvertently opening up the user to a security * hole. */ return (-1); #endif } if (fp == NULL) fp = fopen(fname, "r"); if (fp == NULL) return (-1); while ((ptr = fgetln(fp, &len)) != NULL) { if (len > 0 && ptr[len - 1] == '\n') --len; ptr[len] = '\0'; if (parse_line(el, ptr) == -1) { (void) fclose(fp); return (-1); } } (void) fclose(fp); return (0); } /* el_resize(): * Called from program when terminal is resized */ public void el_resize(EditLine *el) { int lins, cols; sigset_t oset, nset; (void) sigemptyset(&nset); (void) sigaddset(&nset, SIGWINCH); (void) sigprocmask(SIG_BLOCK, &nset, &oset); /* get the correct window size */ if (term_get_size(el, &lins, &cols)) term_change_size(el, lins, cols); (void) sigprocmask(SIG_SETMASK, &oset, NULL); } /* el_beep(): * Called from the program to beep */ public void el_beep(EditLine *el) { term_beep(el); } /* el_editmode() * Set the state of EDIT_DISABLED from the `edit' command. */ protected int /*ARGSUSED*/ el_editmode(EditLine *el, int argc, const char **argv) { const char *how; if (argv == NULL || argc != 2 || argv[1] == NULL) return (-1); how = argv[1]; if (strcmp(how, "on") == 0) { el->el_flags &= ~EDIT_DISABLED; tty_rawmode(el); } else if (strcmp(how, "off") == 0) { tty_cookedmode(el); el->el_flags |= EDIT_DISABLED; } else { (void) fprintf(el->el_errfile, "edit: Bad value `%s'.\n", how); return (-1); } return (0); } Index: head/lib/libedit/el.h =================================================================== --- head/lib/libedit/el.h (revision 170510) +++ head/lib/libedit/el.h (revision 170511) @@ -1,149 +1,150 @@ /*- * 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. 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. * * @(#)el.h 8.1 (Berkeley) 6/4/93 - * $NetBSD: el.h,v 1.16 2003/10/18 23:48:42 christos Exp $ + * $NetBSD: el.h,v 1.17 2006/12/15 22:13:33 christos Exp $ * $FreeBSD$ */ /* * el.h: Internal structures. */ #ifndef _h_el #define _h_el /* * Local defaults */ #define KSHVI #define VIDEFAULT #define ANCHOR #include #include #define EL_BUFSIZ 1024 /* Maximum line size */ #define HANDLE_SIGNALS 0x01 #define NO_TTY 0x02 #define EDIT_DISABLED 0x04 #define UNBUFFERED 0x08 typedef int bool_t; /* True or not */ typedef unsigned char el_action_t; /* Index to command array */ typedef struct coord_t { /* Position on the screen */ int h; int v; } coord_t; typedef struct el_line_t { char *buffer; /* Input line */ char *cursor; /* Cursor position */ char *lastchar; /* Last character */ const char *limit; /* Max position */ } el_line_t; /* * Editor state */ typedef struct el_state_t { int inputmode; /* What mode are we in? */ int doingarg; /* Are we getting an argument? */ int argument; /* Numeric argument */ int metanext; /* Is the next char a meta char */ el_action_t lastcmd; /* Previous command */ el_action_t thiscmd; /* this command */ char thisch; /* char that generated it */ } el_state_t; /* * Until we come up with something better... */ #define el_strdup(a) strdup(a) #define el_malloc(a) malloc(a) #define el_realloc(a,b) realloc(a, b) #define el_free(a) free(a) #include "tty.h" #include "prompt.h" #include "key.h" #include "term.h" #include "refresh.h" #include "chared.h" #include "common.h" #include "search.h" #include "hist.h" #include "map.h" #include "parse.h" #include "sig.h" #include "help.h" #include "read.h" struct editline { char *el_prog; /* the program name */ + FILE *el_infile; /* Stdio stuff */ FILE *el_outfile; /* Stdio stuff */ FILE *el_errfile; /* Stdio stuff */ int el_infd; /* Input file descriptor */ int el_flags; /* Various flags. */ coord_t el_cursor; /* Cursor location */ char **el_display; /* Real screen image = what is there */ char **el_vdisplay; /* Virtual screen image = what we see */ void *el_data; /* Client data */ el_line_t el_line; /* The current line information */ el_state_t el_state; /* Current editor state */ el_term_t el_term; /* Terminal dependent stuff */ el_tty_t el_tty; /* Tty dependent stuff */ el_refresh_t el_refresh; /* Refresh stuff */ el_prompt_t el_prompt; /* Prompt stuff */ el_prompt_t el_rprompt; /* Prompt stuff */ el_chared_t el_chared; /* Characted editor stuff */ el_map_t el_map; /* Key mapping stuff */ el_key_t el_key; /* Key binding stuff */ el_history_t el_history; /* History stuff */ el_search_t el_search; /* Search stuff */ el_signal_t el_signal; /* Signal handling stuff */ el_read_t el_read; /* Character reading stuff */ }; protected int el_editmode(EditLine *, int, const char **); #ifdef DEBUG #define EL_ABORT(a) do { \ fprintf(el->el_errfile, "%s, %d: ", \ __FILE__, __LINE__); \ fprintf a; \ abort(); \ } while( /*CONSTCOND*/0); #else #define EL_ABORT(a) abort() #endif #endif /* _h_el */ Index: head/lib/libedit/term.c =================================================================== --- head/lib/libedit/term.c (revision 170510) +++ head/lib/libedit/term.c (revision 170511) @@ -1,1616 +1,1670 @@ /*- * 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. 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. * - * $NetBSD: term.c,v 1.45 2006/03/18 19:23:14 christos Exp $ + * $NetBSD: term.c,v 1.46 2006/11/24 00:01:17 christos Exp $ */ #if !defined(lint) && !defined(SCCSID) static char sccsid[] = "@(#)term.c 8.2 (Berkeley) 4/30/95"; #endif /* not lint && not SCCSID */ #include __FBSDID("$FreeBSD$"); /* * term.c: Editor/termcap-curses interface * We have to declare a static variable here, since the * termcap putchar routine does not take an argument! */ #include #include #include #include #include #include #include #include #include #include #include #include "el.h" /* * IMPORTANT NOTE: these routines are allowed to look at the current screen * and the current possition assuming that it is correct. If this is not * true, then the update will be WRONG! This is (should be) a valid * assumption... */ #define TC_BUFSIZE 2048 #define GoodStr(a) (el->el_term.t_str[a] != NULL && \ el->el_term.t_str[a][0] != '\0') #define Str(a) el->el_term.t_str[a] #define Val(a) el->el_term.t_val[a] #ifdef notdef private const struct { const char *b_name; int b_rate; } baud_rate[] = { #ifdef B0 { "0", B0 }, #endif #ifdef B50 { "50", B50 }, #endif #ifdef B75 { "75", B75 }, #endif #ifdef B110 { "110", B110 }, #endif #ifdef B134 { "134", B134 }, #endif #ifdef B150 { "150", B150 }, #endif #ifdef B200 { "200", B200 }, #endif #ifdef B300 { "300", B300 }, #endif #ifdef B600 { "600", B600 }, #endif #ifdef B900 { "900", B900 }, #endif #ifdef B1200 { "1200", B1200 }, #endif #ifdef B1800 { "1800", B1800 }, #endif #ifdef B2400 { "2400", B2400 }, #endif #ifdef B3600 { "3600", B3600 }, #endif #ifdef B4800 { "4800", B4800 }, #endif #ifdef B7200 { "7200", B7200 }, #endif #ifdef B9600 { "9600", B9600 }, #endif #ifdef EXTA { "19200", EXTA }, #endif #ifdef B19200 { "19200", B19200 }, #endif #ifdef EXTB { "38400", EXTB }, #endif #ifdef B38400 { "38400", B38400 }, #endif { NULL, 0 } }; #endif private const struct termcapstr { const char *name; const char *long_name; } tstr[] = { #define T_al 0 { "al", "add new blank line" }, #define T_bl 1 { "bl", "audible bell" }, #define T_cd 2 { "cd", "clear to bottom" }, #define T_ce 3 { "ce", "clear to end of line" }, #define T_ch 4 { "ch", "cursor to horiz pos" }, #define T_cl 5 { "cl", "clear screen" }, #define T_dc 6 { "dc", "delete a character" }, #define T_dl 7 { "dl", "delete a line" }, #define T_dm 8 { "dm", "start delete mode" }, #define T_ed 9 { "ed", "end delete mode" }, #define T_ei 10 { "ei", "end insert mode" }, #define T_fs 11 { "fs", "cursor from status line" }, #define T_ho 12 { "ho", "home cursor" }, #define T_ic 13 { "ic", "insert character" }, #define T_im 14 { "im", "start insert mode" }, #define T_ip 15 { "ip", "insert padding" }, #define T_kd 16 { "kd", "sends cursor down" }, #define T_kl 17 { "kl", "sends cursor left" }, #define T_kr 18 { "kr", "sends cursor right" }, #define T_ku 19 { "ku", "sends cursor up" }, #define T_md 20 { "md", "begin bold" }, #define T_me 21 { "me", "end attributes" }, #define T_nd 22 { "nd", "non destructive space" }, #define T_se 23 { "se", "end standout" }, #define T_so 24 { "so", "begin standout" }, #define T_ts 25 { "ts", "cursor to status line" }, #define T_up 26 { "up", "cursor up one" }, #define T_us 27 { "us", "begin underline" }, #define T_ue 28 { "ue", "end underline" }, #define T_vb 29 { "vb", "visible bell" }, #define T_DC 30 { "DC", "delete multiple chars" }, #define T_DO 31 { "DO", "cursor down multiple" }, #define T_IC 32 { "IC", "insert multiple chars" }, #define T_LE 33 { "LE", "cursor left multiple" }, #define T_RI 34 { "RI", "cursor right multiple" }, #define T_UP 35 { "UP", "cursor up multiple" }, #define T_kh 36 { "kh", "send cursor home" }, #define T_at7 37 { "@7", "send cursor end" }, #define T_str 38 { NULL, NULL } }; private const struct termcapval { const char *name; const char *long_name; } tval[] = { #define T_am 0 { "am", "has automatic margins" }, #define T_pt 1 { "pt", "has physical tabs" }, #define T_li 2 { "li", "Number of lines" }, #define T_co 3 { "co", "Number of columns" }, #define T_km 4 { "km", "Has meta key" }, #define T_xt 5 { "xt", "Tab chars destructive" }, #define T_xn 6 { "xn", "newline ignored at right margin" }, #define T_MT 7 { "MT", "Has meta key" }, /* XXX? */ #define T_val 8 { NULL, NULL, } }; /* do two or more of the attributes use me */ private void term_setflags(EditLine *); private int term_rebuffer_display(EditLine *); private void term_free_display(EditLine *); private int term_alloc_display(EditLine *); private void term_alloc(EditLine *, const struct termcapstr *, const char *); private void term_init_arrow(EditLine *); private void term_reset_arrow(EditLine *); private FILE *term_outfile = NULL; /* XXX: How do we fix that? */ /* term_setflags(): * Set the terminal capability flags */ private void term_setflags(EditLine *el) { EL_FLAGS = 0; if (el->el_tty.t_tabs) EL_FLAGS |= (Val(T_pt) && !Val(T_xt)) ? TERM_CAN_TAB : 0; EL_FLAGS |= (Val(T_km) || Val(T_MT)) ? TERM_HAS_META : 0; EL_FLAGS |= GoodStr(T_ce) ? TERM_CAN_CEOL : 0; EL_FLAGS |= (GoodStr(T_dc) || GoodStr(T_DC)) ? TERM_CAN_DELETE : 0; EL_FLAGS |= (GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC)) ? TERM_CAN_INSERT : 0; EL_FLAGS |= (GoodStr(T_up) || GoodStr(T_UP)) ? TERM_CAN_UP : 0; EL_FLAGS |= Val(T_am) ? TERM_HAS_AUTO_MARGINS : 0; EL_FLAGS |= Val(T_xn) ? TERM_HAS_MAGIC_MARGINS : 0; if (GoodStr(T_me) && GoodStr(T_ue)) EL_FLAGS |= (strcmp(Str(T_me), Str(T_ue)) == 0) ? TERM_CAN_ME : 0; else EL_FLAGS &= ~TERM_CAN_ME; if (GoodStr(T_me) && GoodStr(T_se)) EL_FLAGS |= (strcmp(Str(T_me), Str(T_se)) == 0) ? TERM_CAN_ME : 0; #ifdef DEBUG_SCREEN if (!EL_CAN_UP) { (void) fprintf(el->el_errfile, "WARNING: Your terminal cannot move up.\n"); (void) fprintf(el->el_errfile, "Editing may be odd for long lines.\n"); } if (!EL_CAN_CEOL) (void) fprintf(el->el_errfile, "no clear EOL capability.\n"); if (!EL_CAN_DELETE) (void) fprintf(el->el_errfile, "no delete char capability.\n"); if (!EL_CAN_INSERT) (void) fprintf(el->el_errfile, "no insert char capability.\n"); #endif /* DEBUG_SCREEN */ } /* term_init(): * Initialize the terminal stuff */ protected int term_init(EditLine *el) { el->el_term.t_buf = (char *) el_malloc(TC_BUFSIZE); if (el->el_term.t_buf == NULL) return (-1); el->el_term.t_cap = (char *) el_malloc(TC_BUFSIZE); if (el->el_term.t_cap == NULL) return (-1); el->el_term.t_fkey = (fkey_t *) el_malloc(A_K_NKEYS * sizeof(fkey_t)); if (el->el_term.t_fkey == NULL) return (-1); el->el_term.t_loc = 0; el->el_term.t_str = (char **) el_malloc(T_str * sizeof(char *)); if (el->el_term.t_str == NULL) return (-1); (void) memset(el->el_term.t_str, 0, T_str * sizeof(char *)); el->el_term.t_val = (int *) el_malloc(T_val * sizeof(int)); if (el->el_term.t_val == NULL) return (-1); (void) memset(el->el_term.t_val, 0, T_val * sizeof(int)); term_outfile = el->el_outfile; term_init_arrow(el); (void) term_set(el, NULL); return (0); } /* term_end(): * Clean up the terminal stuff */ protected void term_end(EditLine *el) { el_free((ptr_t) el->el_term.t_buf); el->el_term.t_buf = NULL; el_free((ptr_t) el->el_term.t_cap); el->el_term.t_cap = NULL; el->el_term.t_loc = 0; el_free((ptr_t) el->el_term.t_str); el->el_term.t_str = NULL; el_free((ptr_t) el->el_term.t_val); el->el_term.t_val = NULL; el_free((ptr_t) el->el_term.t_fkey); el->el_term.t_fkey = NULL; term_free_display(el); } /* term_alloc(): * Maintain a string pool for termcap strings */ private void term_alloc(EditLine *el, const struct termcapstr *t, const char *cap) { char termbuf[TC_BUFSIZE]; int tlen, clen; char **tlist = el->el_term.t_str; char **tmp, **str = &tlist[t - tstr]; if (cap == NULL || *cap == '\0') { *str = NULL; return; } else clen = strlen(cap); tlen = *str == NULL ? 0 : strlen(*str); /* * New string is shorter; no need to allocate space */ if (clen <= tlen) { if (*str) (void) strcpy(*str, cap); /* XXX strcpy is safe */ return; } /* * New string is longer; see if we have enough space to append */ if (el->el_term.t_loc + 3 < TC_BUFSIZE) { /* XXX strcpy is safe */ (void) strcpy(*str = &el->el_term.t_buf[el->el_term.t_loc], cap); el->el_term.t_loc += clen + 1; /* one for \0 */ return; } /* * Compact our buffer; no need to check compaction, cause we know it * fits... */ tlen = 0; for (tmp = tlist; tmp < &tlist[T_str]; tmp++) if (*tmp != NULL && *tmp != '\0' && *tmp != *str) { char *ptr; for (ptr = *tmp; *ptr != '\0'; termbuf[tlen++] = *ptr++) continue; termbuf[tlen++] = '\0'; } memcpy(el->el_term.t_buf, termbuf, TC_BUFSIZE); el->el_term.t_loc = tlen; if (el->el_term.t_loc + 3 >= TC_BUFSIZE) { (void) fprintf(el->el_errfile, "Out of termcap string space.\n"); return; } /* XXX strcpy is safe */ (void) strcpy(*str = &el->el_term.t_buf[el->el_term.t_loc], cap); el->el_term.t_loc += clen + 1; /* one for \0 */ return; } /* term_rebuffer_display(): * Rebuffer the display after the screen changed size */ private int term_rebuffer_display(EditLine *el) { coord_t *c = &el->el_term.t_size; term_free_display(el); c->h = Val(T_co); c->v = Val(T_li); if (term_alloc_display(el) == -1) return (-1); return (0); } /* term_alloc_display(): * Allocate a new display. */ private int term_alloc_display(EditLine *el) { int i; char **b; coord_t *c = &el->el_term.t_size; b = (char **) el_malloc((size_t) (sizeof(char *) * (c->v + 1))); if (b == NULL) return (-1); for (i = 0; i < c->v; i++) { b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1))); if (b[i] == NULL) { while (--i >= 0) el_free((ptr_t) b[i]); el_free((ptr_t) b); return (-1); } } b[c->v] = NULL; el->el_display = b; b = (char **) el_malloc((size_t) (sizeof(char *) * (c->v + 1))); if (b == NULL) return (-1); for (i = 0; i < c->v; i++) { b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1))); if (b[i] == NULL) { while (--i >= 0) el_free((ptr_t) b[i]); el_free((ptr_t) b); return (-1); } } b[c->v] = NULL; el->el_vdisplay = b; return (0); } /* term_free_display(): * Free the display buffers */ private void term_free_display(EditLine *el) { char **b; char **bufp; b = el->el_display; el->el_display = NULL; if (b != NULL) { for (bufp = b; *bufp != NULL; bufp++) el_free((ptr_t) * bufp); el_free((ptr_t) b); } b = el->el_vdisplay; el->el_vdisplay = NULL; if (b != NULL) { for (bufp = b; *bufp != NULL; bufp++) el_free((ptr_t) * bufp); el_free((ptr_t) b); } } /* term_move_to_line(): * move to line (first line == 0) * as efficiently as possible */ protected void term_move_to_line(EditLine *el, int where) { int del; if (where == el->el_cursor.v) return; if (where > el->el_term.t_size.v) { #ifdef DEBUG_SCREEN (void) fprintf(el->el_errfile, "term_move_to_line: where is ridiculous: %d\r\n", where); #endif /* DEBUG_SCREEN */ return; } if ((del = where - el->el_cursor.v) > 0) { while (del > 0) { if (EL_HAS_AUTO_MARGINS && el->el_display[el->el_cursor.v][0] != '\0') { /* move without newline */ term_move_to_char(el, el->el_term.t_size.h - 1); term_overwrite(el, &el->el_display[el->el_cursor.v][el->el_cursor.h], 1); /* updates Cursor */ del--; } else { if ((del > 1) && GoodStr(T_DO)) { (void) tputs(tgoto(Str(T_DO), del, del), del, term__putc); del = 0; } else { for (; del > 0; del--) term__putc('\n'); /* because the \n will become \r\n */ el->el_cursor.h = 0; } } } } else { /* del < 0 */ if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up))) (void) tputs(tgoto(Str(T_UP), -del, -del), -del, term__putc); else { if (GoodStr(T_up)) for (; del < 0; del++) (void) tputs(Str(T_up), 1, term__putc); } } el->el_cursor.v = where;/* now where is here */ } /* term_move_to_char(): * Move to the character position specified */ protected void term_move_to_char(EditLine *el, int where) { int del, i; mc_again: if (where == el->el_cursor.h) return; if (where > el->el_term.t_size.h) { #ifdef DEBUG_SCREEN (void) fprintf(el->el_errfile, "term_move_to_char: where is riduculous: %d\r\n", where); #endif /* DEBUG_SCREEN */ return; } if (!where) { /* if where is first column */ term__putc('\r'); /* do a CR */ el->el_cursor.h = 0; return; } del = where - el->el_cursor.h; if ((del < -4 || del > 4) && GoodStr(T_ch)) /* go there directly */ (void) tputs(tgoto(Str(T_ch), where, where), where, term__putc); else { if (del > 0) { /* moving forward */ if ((del > 4) && GoodStr(T_RI)) (void) tputs(tgoto(Str(T_RI), del, del), del, term__putc); else { /* if I can do tabs, use them */ if (EL_CAN_TAB) { if ((el->el_cursor.h & 0370) != (where & 0370)) { /* if not within tab stop */ for (i = (el->el_cursor.h & 0370); i < (where & 0370); i += 8) term__putc('\t'); /* then tab over */ el->el_cursor.h = where & 0370; } } /* * it's usually cheaper to just write the * chars, so we do. */ /* * NOTE THAT term_overwrite() WILL CHANGE * el->el_cursor.h!!! */ term_overwrite(el, &el->el_display[el->el_cursor.v][el->el_cursor.h], where - el->el_cursor.h); } } else { /* del < 0 := moving backward */ if ((-del > 4) && GoodStr(T_LE)) (void) tputs(tgoto(Str(T_LE), -del, -del), -del, term__putc); else { /* can't go directly there */ /* * if the "cost" is greater than the "cost" * from col 0 */ if (EL_CAN_TAB ? ((unsigned int)-del > (((unsigned int) where >> 3) + (where & 07))) : (-del > where)) { term__putc('\r'); /* do a CR */ el->el_cursor.h = 0; goto mc_again; /* and try again */ } for (i = 0; i < -del; i++) term__putc('\b'); } } } el->el_cursor.h = where; /* now where is here */ } /* term_overwrite(): * Overstrike num characters */ protected void term_overwrite(EditLine *el, const char *cp, int n) { if (n <= 0) return; /* catch bugs */ if (n > el->el_term.t_size.h) { #ifdef DEBUG_SCREEN (void) fprintf(el->el_errfile, "term_overwrite: n is riduculous: %d\r\n", n); #endif /* DEBUG_SCREEN */ return; } do { term__putc(*cp++); el->el_cursor.h++; } while (--n); if (el->el_cursor.h >= el->el_term.t_size.h) { /* wrap? */ if (EL_HAS_AUTO_MARGINS) { /* yes */ el->el_cursor.h = 0; el->el_cursor.v++; if (EL_HAS_MAGIC_MARGINS) { /* force the wrap to avoid the "magic" * situation */ char c; if ((c = el->el_display[el->el_cursor.v][el->el_cursor.h]) != '\0') term_overwrite(el, &c, 1); else term__putc(' '); el->el_cursor.h = 1; } } else /* no wrap, but cursor stays on screen */ el->el_cursor.h = el->el_term.t_size.h; } } /* term_deletechars(): * Delete num characters */ protected void term_deletechars(EditLine *el, int num) { if (num <= 0) return; if (!EL_CAN_DELETE) { #ifdef DEBUG_EDIT (void) fprintf(el->el_errfile, " ERROR: cannot delete \n"); #endif /* DEBUG_EDIT */ return; } if (num > el->el_term.t_size.h) { #ifdef DEBUG_SCREEN (void) fprintf(el->el_errfile, "term_deletechars: num is riduculous: %d\r\n", num); #endif /* DEBUG_SCREEN */ return; } if (GoodStr(T_DC)) /* if I have multiple delete */ if ((num > 1) || !GoodStr(T_dc)) { /* if dc would be more * expen. */ (void) tputs(tgoto(Str(T_DC), num, num), num, term__putc); return; } if (GoodStr(T_dm)) /* if I have delete mode */ (void) tputs(Str(T_dm), 1, term__putc); if (GoodStr(T_dc)) /* else do one at a time */ while (num--) (void) tputs(Str(T_dc), 1, term__putc); if (GoodStr(T_ed)) /* if I have delete mode */ (void) tputs(Str(T_ed), 1, term__putc); } /* term_insertwrite(): * Puts terminal in insert character mode or inserts num * characters in the line */ protected void term_insertwrite(EditLine *el, char *cp, int num) { if (num <= 0) return; if (!EL_CAN_INSERT) { #ifdef DEBUG_EDIT (void) fprintf(el->el_errfile, " ERROR: cannot insert \n"); #endif /* DEBUG_EDIT */ return; } if (num > el->el_term.t_size.h) { #ifdef DEBUG_SCREEN (void) fprintf(el->el_errfile, "StartInsert: num is riduculous: %d\r\n", num); #endif /* DEBUG_SCREEN */ return; } if (GoodStr(T_IC)) /* if I have multiple insert */ if ((num > 1) || !GoodStr(T_ic)) { /* if ic would be more expensive */ (void) tputs(tgoto(Str(T_IC), num, num), num, term__putc); term_overwrite(el, cp, num); /* this updates el_cursor.h */ return; } if (GoodStr(T_im) && GoodStr(T_ei)) { /* if I have insert mode */ (void) tputs(Str(T_im), 1, term__putc); el->el_cursor.h += num; do term__putc(*cp++); while (--num); if (GoodStr(T_ip)) /* have to make num chars insert */ (void) tputs(Str(T_ip), 1, term__putc); (void) tputs(Str(T_ei), 1, term__putc); return; } do { if (GoodStr(T_ic)) /* have to make num chars insert */ (void) tputs(Str(T_ic), 1, term__putc); /* insert a char */ term__putc(*cp++); el->el_cursor.h++; if (GoodStr(T_ip)) /* have to make num chars insert */ (void) tputs(Str(T_ip), 1, term__putc); /* pad the inserted char */ } while (--num); } /* term_clear_EOL(): * clear to end of line. There are num characters to clear */ protected void term_clear_EOL(EditLine *el, int num) { int i; if (EL_CAN_CEOL && GoodStr(T_ce)) (void) tputs(Str(T_ce), 1, term__putc); else { for (i = 0; i < num; i++) term__putc(' '); el->el_cursor.h += num; /* have written num spaces */ } } /* term_clear_screen(): * Clear the screen */ protected void term_clear_screen(EditLine *el) { /* clear the whole screen and home */ if (GoodStr(T_cl)) /* send the clear screen code */ (void) tputs(Str(T_cl), Val(T_li), term__putc); else if (GoodStr(T_ho) && GoodStr(T_cd)) { (void) tputs(Str(T_ho), Val(T_li), term__putc); /* home */ /* clear to bottom of screen */ (void) tputs(Str(T_cd), Val(T_li), term__putc); } else { term__putc('\r'); term__putc('\n'); } } /* term_beep(): * Beep the way the terminal wants us */ protected void term_beep(EditLine *el) { if (GoodStr(T_bl)) /* what termcap says we should use */ (void) tputs(Str(T_bl), 1, term__putc); else term__putc('\007'); /* an ASCII bell; ^G */ } #ifdef notdef /* term_clear_to_bottom(): * Clear to the bottom of the screen */ protected void term_clear_to_bottom(EditLine *el) { if (GoodStr(T_cd)) (void) tputs(Str(T_cd), Val(T_li), term__putc); else if (GoodStr(T_ce)) (void) tputs(Str(T_ce), Val(T_li), term__putc); } #endif protected void term_get(EditLine *el, const char **term) { *term = el->el_term.t_name; } /* term_set(): * Read in the terminal capabilities from the requested terminal */ protected int term_set(EditLine *el, const char *term) { int i; char buf[TC_BUFSIZE]; char *area; const struct termcapstr *t; sigset_t oset, nset; int lins, cols; (void) sigemptyset(&nset); (void) sigaddset(&nset, SIGWINCH); (void) sigprocmask(SIG_BLOCK, &nset, &oset); area = buf; if (term == NULL) term = getenv("TERM"); if (!term || !term[0]) term = "dumb"; if (strcmp(term, "emacs") == 0) el->el_flags |= EDIT_DISABLED; memset(el->el_term.t_cap, 0, TC_BUFSIZE); i = tgetent(el->el_term.t_cap, term); if (i <= 0) { if (i == -1) (void) fprintf(el->el_errfile, "Cannot read termcap database;\n"); else if (i == 0) (void) fprintf(el->el_errfile, "No entry for terminal type \"%s\";\n", term); (void) fprintf(el->el_errfile, "using dumb terminal settings.\n"); Val(T_co) = 80; /* do a dumb terminal */ Val(T_pt) = Val(T_km) = Val(T_li) = 0; Val(T_xt) = Val(T_MT); for (t = tstr; t->name != NULL; t++) term_alloc(el, t, NULL); } else { /* auto/magic margins */ Val(T_am) = tgetflag("am"); Val(T_xn) = tgetflag("xn"); /* Can we tab */ Val(T_pt) = tgetflag("pt"); Val(T_xt) = tgetflag("xt"); /* do we have a meta? */ Val(T_km) = tgetflag("km"); Val(T_MT) = tgetflag("MT"); /* Get the size */ Val(T_co) = tgetnum("co"); Val(T_li) = tgetnum("li"); for (t = tstr; t->name != NULL; t++) { /* XXX: some systems' tgetstr needs non const */ term_alloc(el, t, tgetstr(strchr(t->name, *t->name), &area)); } } if (Val(T_co) < 2) Val(T_co) = 80; /* just in case */ if (Val(T_li) < 1) Val(T_li) = 24; el->el_term.t_size.v = Val(T_co); el->el_term.t_size.h = Val(T_li); term_setflags(el); /* get the correct window size */ (void) term_get_size(el, &lins, &cols); if (term_change_size(el, lins, cols) == -1) return (-1); (void) sigprocmask(SIG_SETMASK, &oset, NULL); term_bind_arrow(el); el->el_term.t_name = term; return (i <= 0 ? -1 : 0); } /* term_get_size(): * Return the new window size in lines and cols, and * true if the size was changed. */ protected int term_get_size(EditLine *el, int *lins, int *cols) { *cols = Val(T_co); *lins = Val(T_li); #ifdef TIOCGWINSZ { struct winsize ws; if (ioctl(el->el_infd, TIOCGWINSZ, (ioctl_t) & ws) != -1) { if (ws.ws_col) *cols = ws.ws_col; if (ws.ws_row) *lins = ws.ws_row; } } #endif #ifdef TIOCGSIZE { struct ttysize ts; if (ioctl(el->el_infd, TIOCGSIZE, (ioctl_t) & ts) != -1) { if (ts.ts_cols) *cols = ts.ts_cols; if (ts.ts_lines) *lins = ts.ts_lines; } } #endif return (Val(T_co) != *cols || Val(T_li) != *lins); } /* term_change_size(): * Change the size of the terminal */ protected int term_change_size(EditLine *el, int lins, int cols) { /* * Just in case */ Val(T_co) = (cols < 2) ? 80 : cols; Val(T_li) = (lins < 1) ? 24 : lins; /* re-make display buffers */ if (term_rebuffer_display(el) == -1) return (-1); re_clear_display(el); return (0); } /* term_init_arrow(): * Initialize the arrow key bindings from termcap */ private void term_init_arrow(EditLine *el) { fkey_t *arrow = el->el_term.t_fkey; arrow[A_K_DN].name = "down"; arrow[A_K_DN].key = T_kd; arrow[A_K_DN].fun.cmd = ED_NEXT_HISTORY; arrow[A_K_DN].type = XK_CMD; arrow[A_K_UP].name = "up"; arrow[A_K_UP].key = T_ku; arrow[A_K_UP].fun.cmd = ED_PREV_HISTORY; arrow[A_K_UP].type = XK_CMD; arrow[A_K_LT].name = "left"; arrow[A_K_LT].key = T_kl; arrow[A_K_LT].fun.cmd = ED_PREV_CHAR; arrow[A_K_LT].type = XK_CMD; arrow[A_K_RT].name = "right"; arrow[A_K_RT].key = T_kr; arrow[A_K_RT].fun.cmd = ED_NEXT_CHAR; arrow[A_K_RT].type = XK_CMD; arrow[A_K_HO].name = "home"; arrow[A_K_HO].key = T_kh; arrow[A_K_HO].fun.cmd = ED_MOVE_TO_BEG; arrow[A_K_HO].type = XK_CMD; arrow[A_K_EN].name = "end"; arrow[A_K_EN].key = T_at7; arrow[A_K_EN].fun.cmd = ED_MOVE_TO_END; arrow[A_K_EN].type = XK_CMD; } /* term_reset_arrow(): * Reset arrow key bindings */ private void term_reset_arrow(EditLine *el) { fkey_t *arrow = el->el_term.t_fkey; static const char strA[] = {033, '[', 'A', '\0'}; static const char strB[] = {033, '[', 'B', '\0'}; static const char strC[] = {033, '[', 'C', '\0'}; static const char strD[] = {033, '[', 'D', '\0'}; static const char strH[] = {033, '[', 'H', '\0'}; static const char strF[] = {033, '[', 'F', '\0'}; static const char str1[] = {033, '[', '1', '~', '\0'}; static const char str4[] = {033, '[', '4', '~', '\0'}; static const char stOA[] = {033, 'O', 'A', '\0'}; static const char stOB[] = {033, 'O', 'B', '\0'}; static const char stOC[] = {033, 'O', 'C', '\0'}; static const char stOD[] = {033, 'O', 'D', '\0'}; static const char stOH[] = {033, 'O', 'H', '\0'}; static const char stOF[] = {033, 'O', 'F', '\0'}; key_add(el, strA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); key_add(el, strB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); key_add(el, strC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); key_add(el, strD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); key_add(el, strH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); key_add(el, strF, &arrow[A_K_EN].fun, arrow[A_K_EN].type); key_add(el, str1, &arrow[A_K_HO].fun, arrow[A_K_HO].type); key_add(el, str4, &arrow[A_K_EN].fun, arrow[A_K_EN].type); key_add(el, stOA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); key_add(el, stOB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); key_add(el, stOC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); key_add(el, stOD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); key_add(el, stOH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); key_add(el, stOF, &arrow[A_K_EN].fun, arrow[A_K_EN].type); if (el->el_map.type == MAP_VI) { key_add(el, &strA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); key_add(el, &strB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); key_add(el, &strC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); key_add(el, &strD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); key_add(el, &strH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); key_add(el, &strF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); key_add(el, &str1[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); key_add(el, &str4[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); key_add(el, &stOA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); key_add(el, &stOB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); key_add(el, &stOC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); key_add(el, &stOD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); key_add(el, &stOH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); key_add(el, &stOF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); } } /* term_set_arrow(): * Set an arrow key binding */ protected int term_set_arrow(EditLine *el, const char *name, key_value_t *fun, int type) { fkey_t *arrow = el->el_term.t_fkey; int i; for (i = 0; i < A_K_NKEYS; i++) if (strcmp(name, arrow[i].name) == 0) { arrow[i].fun = *fun; arrow[i].type = type; return (0); } return (-1); } /* term_clear_arrow(): * Clear an arrow key binding */ protected int term_clear_arrow(EditLine *el, const char *name) { fkey_t *arrow = el->el_term.t_fkey; int i; for (i = 0; i < A_K_NKEYS; i++) if (strcmp(name, arrow[i].name) == 0) { arrow[i].type = XK_NOD; return (0); } return (-1); } /* term_print_arrow(): * Print the arrow key bindings */ protected void term_print_arrow(EditLine *el, const char *name) { int i; fkey_t *arrow = el->el_term.t_fkey; for (i = 0; i < A_K_NKEYS; i++) if (*name == '\0' || strcmp(name, arrow[i].name) == 0) if (arrow[i].type != XK_NOD) key_kprint(el, arrow[i].name, &arrow[i].fun, arrow[i].type); } /* term_bind_arrow(): * Bind the arrow keys */ protected void term_bind_arrow(EditLine *el) { el_action_t *map; const el_action_t *dmap; int i, j; char *p; fkey_t *arrow = el->el_term.t_fkey; /* Check if the components needed are initialized */ if (el->el_term.t_buf == NULL || el->el_map.key == NULL) return; map = el->el_map.type == MAP_VI ? el->el_map.alt : el->el_map.key; dmap = el->el_map.type == MAP_VI ? el->el_map.vic : el->el_map.emacs; term_reset_arrow(el); for (i = 0; i < A_K_NKEYS; i++) { p = el->el_term.t_str[arrow[i].key]; if (p && *p) { j = (unsigned char) *p; /* * Assign the arrow keys only if: * * 1. They are multi-character arrow keys and the user * has not re-assigned the leading character, or * has re-assigned the leading character to be * ED_SEQUENCE_LEAD_IN * 2. They are single arrow keys pointing to an * unassigned key. */ if (arrow[i].type == XK_NOD) key_clear(el, map, p); else { if (p[1] && (dmap[j] == map[j] || map[j] == ED_SEQUENCE_LEAD_IN)) { key_add(el, p, &arrow[i].fun, arrow[i].type); map[j] = ED_SEQUENCE_LEAD_IN; } else if (map[j] == ED_UNASSIGNED) { key_clear(el, map, p); if (arrow[i].type == XK_CMD) map[j] = arrow[i].fun.cmd; else key_add(el, p, &arrow[i].fun, arrow[i].type); } } } } } /* term__putc(): * Add a character */ protected int term__putc(int c) { return (fputc(c, term_outfile)); } /* term__flush(): * Flush output */ protected void term__flush(void) { (void) fflush(term_outfile); } /* term_writec(): * Write the given character out, in a human readable form */ protected void term_writec(EditLine *el, int c) { char buf[8]; int cnt = key__decode_char(buf, sizeof(buf), 0, c); buf[cnt] = '\0'; term_overwrite(el, buf, cnt); term__flush(); } /* term_telltc(): * Print the current termcap characteristics */ protected int /*ARGSUSED*/ term_telltc(EditLine *el, int argc __unused, const char **argv __unused) { const struct termcapstr *t; char **ts; char upbuf[EL_BUFSIZ]; (void) fprintf(el->el_outfile, "\n\tYour terminal has the\n"); (void) fprintf(el->el_outfile, "\tfollowing characteristics:\n\n"); (void) fprintf(el->el_outfile, "\tIt has %d columns and %d lines\n", Val(T_co), Val(T_li)); (void) fprintf(el->el_outfile, "\tIt has %s meta key\n", EL_HAS_META ? "a" : "no"); (void) fprintf(el->el_outfile, "\tIt can%suse tabs\n", EL_CAN_TAB ? " " : "not "); (void) fprintf(el->el_outfile, "\tIt %s automatic margins\n", EL_HAS_AUTO_MARGINS ? "has" : "does not have"); if (EL_HAS_AUTO_MARGINS) (void) fprintf(el->el_outfile, "\tIt %s magic margins\n", EL_HAS_MAGIC_MARGINS ? "has" : "does not have"); for (t = tstr, ts = el->el_term.t_str; t->name != NULL; t++, ts++) { const char *ub; if (*ts && **ts) { (void) key__decode_str(*ts, upbuf, sizeof(upbuf), ""); ub = upbuf; } else { ub = "(empty)"; } (void) fprintf(el->el_outfile, "\t%25s (%s) == %s\n", t->long_name, t->name, ub); } (void) fputc('\n', el->el_outfile); return (0); } /* term_settc(): * Change the current terminal characteristics */ protected int /*ARGSUSED*/ term_settc(EditLine *el, int argc __unused, const char **argv) { const struct termcapstr *ts; const struct termcapval *tv; const char *what, *how; if (argv == NULL || argv[1] == NULL || argv[2] == NULL) - return (-1); + return -1; what = argv[1]; how = argv[2]; /* * Do the strings first */ for (ts = tstr; ts->name != NULL; ts++) if (strcmp(ts->name, what) == 0) break; if (ts->name != NULL) { term_alloc(el, ts, how); term_setflags(el); - return (0); + return 0; } /* * Do the numeric ones second */ for (tv = tval; tv->name != NULL; tv++) if (strcmp(tv->name, what) == 0) break; - if (tv->name != NULL) { - if (tv == &tval[T_pt] || tv == &tval[T_km] || - tv == &tval[T_am] || tv == &tval[T_xn]) { - if (strcmp(how, "yes") == 0) - el->el_term.t_val[tv - tval] = 1; - else if (strcmp(how, "no") == 0) - el->el_term.t_val[tv - tval] = 0; - else { - (void) fprintf(el->el_errfile, - "settc: Bad value `%s'.\n", how); - return (-1); - } - term_setflags(el); - if (term_change_size(el, Val(T_li), Val(T_co)) == -1) - return (-1); - return (0); - } else { - long i; - char *ep; + if (tv->name != NULL) + return -1; - i = strtol(how, &ep, 10); - if (*ep != '\0') { - (void) fprintf(el->el_errfile, - "settc: Bad value `%s'.\n", how); - return (-1); - } - el->el_term.t_val[tv - tval] = (int) i; - el->el_term.t_size.v = Val(T_co); - el->el_term.t_size.h = Val(T_li); - if (tv == &tval[T_co] || tv == &tval[T_li]) - if (term_change_size(el, Val(T_li), Val(T_co)) - == -1) - return (-1); - return (0); + if (tv == &tval[T_pt] || tv == &tval[T_km] || + tv == &tval[T_am] || tv == &tval[T_xn]) { + if (strcmp(how, "yes") == 0) + el->el_term.t_val[tv - tval] = 1; + else if (strcmp(how, "no") == 0) + el->el_term.t_val[tv - tval] = 0; + else { + (void) fprintf(el->el_errfile, + "%s: Bad value `%s'.\n", argv[0], how); + return -1; } + term_setflags(el); + if (term_change_size(el, Val(T_li), Val(T_co)) == -1) + return -1; + return 0; + } else { + long i; + char *ep; + + i = strtol(how, &ep, 10); + if (*ep != '\0') { + (void) fprintf(el->el_errfile, + "%s: Bad value `%s'.\n", argv[0], how); + return -1; + } + el->el_term.t_val[tv - tval] = (int) i; + el->el_term.t_size.v = Val(T_co); + el->el_term.t_size.h = Val(T_li); + if (tv == &tval[T_co] || tv == &tval[T_li]) + if (term_change_size(el, Val(T_li), Val(T_co)) + == -1) + return -1; + return 0; } - return (-1); } + +/* term_gettc(): + * Get the current terminal characteristics + */ +protected int +/*ARGSUSED*/ +term_gettc(EditLine *el, int argc __unused, char **argv) +{ + const struct termcapstr *ts; + const struct termcapval *tv; + char *what; + void *how; + + if (argv == NULL || argv[1] == NULL || argv[2] == NULL) + return (-1); + + what = argv[1]; + how = argv[2]; + + /* + * Do the strings first + */ + for (ts = tstr; ts->name != NULL; ts++) + if (strcmp(ts->name, what) == 0) + break; + + if (ts->name != NULL) { + *(char **)how = el->el_term.t_str[ts - tstr]; + return 0; + } + /* + * Do the numeric ones second + */ + for (tv = tval; tv->name != NULL; tv++) + if (strcmp(tv->name, what) == 0) + break; + + if (tv->name == NULL) + return -1; + + if (tv == &tval[T_pt] || tv == &tval[T_km] || + tv == &tval[T_am] || tv == &tval[T_xn]) { + static char yes[] = "yes"; + static char no[] = "no"; + if (el->el_term.t_val[tv - tval]) + *(char **)how = yes; + else + *(char **)how = no; + return 0; + } else { + *(int *)how = el->el_term.t_val[tv - tval]; + return 0; + } +} /* term_echotc(): * Print the termcap string out with variable substitution */ protected int /*ARGSUSED*/ term_echotc(EditLine *el, int argc __unused, const char **argv) { char *cap, *scap, *ep; int arg_need, arg_cols, arg_rows; int verbose = 0, silent = 0; char *area; static const char fmts[] = "%s\n", fmtd[] = "%d\n"; const struct termcapstr *t; char buf[TC_BUFSIZE]; long i; area = buf; if (argv == NULL || argv[1] == NULL) return (-1); argv++; if (argv[0][0] == '-') { switch (argv[0][1]) { case 'v': verbose = 1; break; case 's': silent = 1; break; default: /* stderror(ERR_NAME | ERR_TCUSAGE); */ break; } argv++; } if (!*argv || *argv[0] == '\0') return (0); if (strcmp(*argv, "tabs") == 0) { (void) fprintf(el->el_outfile, fmts, EL_CAN_TAB ? "yes" : "no"); return (0); } else if (strcmp(*argv, "meta") == 0) { (void) fprintf(el->el_outfile, fmts, Val(T_km) ? "yes" : "no"); return (0); } else if (strcmp(*argv, "xn") == 0) { (void) fprintf(el->el_outfile, fmts, EL_HAS_MAGIC_MARGINS ? "yes" : "no"); return (0); } else if (strcmp(*argv, "am") == 0) { (void) fprintf(el->el_outfile, fmts, EL_HAS_AUTO_MARGINS ? "yes" : "no"); return (0); } else if (strcmp(*argv, "baud") == 0) { #ifdef notdef int i; for (i = 0; baud_rate[i].b_name != NULL; i++) if (el->el_tty.t_speed == baud_rate[i].b_rate) { (void) fprintf(el->el_outfile, fmts, baud_rate[i].b_name); return (0); } (void) fprintf(el->el_outfile, fmtd, 0); #else (void) fprintf(el->el_outfile, fmtd, (int)el->el_tty.t_speed); #endif return (0); } else if (strcmp(*argv, "rows") == 0 || strcmp(*argv, "lines") == 0) { (void) fprintf(el->el_outfile, fmtd, Val(T_li)); return (0); } else if (strcmp(*argv, "cols") == 0) { (void) fprintf(el->el_outfile, fmtd, Val(T_co)); return (0); } /* * Try to use our local definition first */ scap = NULL; for (t = tstr; t->name != NULL; t++) if (strcmp(t->name, *argv) == 0) { scap = el->el_term.t_str[t - tstr]; break; } if (t->name == NULL) { /* XXX: some systems' tgetstr needs non const */ scap = tgetstr(strchr(*argv, **argv), &area); } if (!scap || scap[0] == '\0') { if (!silent) (void) fprintf(el->el_errfile, "echotc: Termcap parameter `%s' not found.\n", *argv); return (-1); } /* * Count home many values we need for this capability. */ for (cap = scap, arg_need = 0; *cap; cap++) if (*cap == '%') switch (*++cap) { case 'd': case '2': case '3': case '.': case '+': arg_need++; break; case '%': case '>': case 'i': case 'r': case 'n': case 'B': case 'D': break; default: /* * hpux has lot's of them... */ if (verbose) (void) fprintf(el->el_errfile, "echotc: Warning: unknown termcap %% `%c'.\n", *cap); /* This is bad, but I won't complain */ break; } switch (arg_need) { case 0: argv++; if (*argv && *argv[0]) { if (!silent) (void) fprintf(el->el_errfile, "echotc: Warning: Extra argument `%s'.\n", *argv); return (-1); } (void) tputs(scap, 1, term__putc); break; case 1: argv++; if (!*argv || *argv[0] == '\0') { if (!silent) (void) fprintf(el->el_errfile, "echotc: Warning: Missing argument.\n"); return (-1); } arg_cols = 0; i = strtol(*argv, &ep, 10); if (*ep != '\0' || i < 0) { if (!silent) (void) fprintf(el->el_errfile, "echotc: Bad value `%s' for rows.\n", *argv); return (-1); } arg_rows = (int) i; argv++; if (*argv && *argv[0]) { if (!silent) (void) fprintf(el->el_errfile, "echotc: Warning: Extra argument `%s'.\n", *argv); return (-1); } (void) tputs(tgoto(scap, arg_cols, arg_rows), 1, term__putc); break; default: /* This is wrong, but I will ignore it... */ if (verbose) (void) fprintf(el->el_errfile, "echotc: Warning: Too many required arguments (%d).\n", arg_need); /* FALLTHROUGH */ case 2: argv++; if (!*argv || *argv[0] == '\0') { if (!silent) (void) fprintf(el->el_errfile, "echotc: Warning: Missing argument.\n"); return (-1); } i = strtol(*argv, &ep, 10); if (*ep != '\0' || i < 0) { if (!silent) (void) fprintf(el->el_errfile, "echotc: Bad value `%s' for cols.\n", *argv); return (-1); } arg_cols = (int) i; argv++; if (!*argv || *argv[0] == '\0') { if (!silent) (void) fprintf(el->el_errfile, "echotc: Warning: Missing argument.\n"); return (-1); } i = strtol(*argv, &ep, 10); if (*ep != '\0' || i < 0) { if (!silent) (void) fprintf(el->el_errfile, "echotc: Bad value `%s' for rows.\n", *argv); return (-1); } arg_rows = (int) i; if (*ep != '\0') { if (!silent) (void) fprintf(el->el_errfile, "echotc: Bad value `%s'.\n", *argv); return (-1); } argv++; if (*argv && *argv[0]) { if (!silent) (void) fprintf(el->el_errfile, "echotc: Warning: Extra argument `%s'.\n", *argv); return (-1); } (void) tputs(tgoto(scap, arg_cols, arg_rows), arg_rows, term__putc); break; } return (0); } Index: head/lib/libedit/term.h =================================================================== --- head/lib/libedit/term.h (revision 170510) +++ head/lib/libedit/term.h (revision 170511) @@ -1,124 +1,125 @@ /*- * 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. 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. * * @(#)term.h 8.1 (Berkeley) 6/4/93 - * $NetBSD: term.h,v 1.17 2006/03/06 21:11:56 christos Exp $ + * $NetBSD: term.h,v 1.18 2006/11/24 00:01:17 christos Exp $ * $FreeBSD$ */ /* * el.term.h: Termcap header */ #ifndef _h_el_term #define _h_el_term #include "histedit.h" typedef struct { /* Symbolic function key bindings */ const char *name; /* name of the key */ int key; /* Index in termcap table */ key_value_t fun; /* Function bound to it */ int type; /* Type of function */ } fkey_t; typedef struct { const char *t_name; /* the terminal name */ coord_t t_size; /* # lines and cols */ int t_flags; #define TERM_CAN_INSERT 0x001 /* Has insert cap */ #define TERM_CAN_DELETE 0x002 /* Has delete cap */ #define TERM_CAN_CEOL 0x004 /* Has CEOL cap */ #define TERM_CAN_TAB 0x008 /* Can use tabs */ #define TERM_CAN_ME 0x010 /* Can turn all attrs. */ #define TERM_CAN_UP 0x020 /* Can move up */ #define TERM_HAS_META 0x040 /* Has a meta key */ #define TERM_HAS_AUTO_MARGINS 0x080 /* Has auto margins */ #define TERM_HAS_MAGIC_MARGINS 0x100 /* Has magic margins */ char *t_buf; /* Termcap buffer */ int t_loc; /* location used */ char **t_str; /* termcap strings */ int *t_val; /* termcap values */ char *t_cap; /* Termcap buffer */ fkey_t *t_fkey; /* Array of keys */ } el_term_t; /* * fKey indexes */ #define A_K_DN 0 #define A_K_UP 1 #define A_K_LT 2 #define A_K_RT 3 #define A_K_HO 4 #define A_K_EN 5 #define A_K_NKEYS 6 protected void term_move_to_line(EditLine *, int); protected void term_move_to_char(EditLine *, int); protected void term_clear_EOL(EditLine *, int); protected void term_overwrite(EditLine *, const char *, int); protected void term_insertwrite(EditLine *, char *, int); protected void term_deletechars(EditLine *, int); protected void term_clear_screen(EditLine *); protected void term_beep(EditLine *); protected int term_change_size(EditLine *, int, int); protected int term_get_size(EditLine *, int *, int *); protected int term_init(EditLine *); protected void term_bind_arrow(EditLine *); protected void term_print_arrow(EditLine *, const char *); protected int term_clear_arrow(EditLine *, const char *); protected int term_set_arrow(EditLine *, const char *, key_value_t *, int); protected void term_end(EditLine *); protected void term_get(EditLine *, const char **); protected int term_set(EditLine *, const char *); protected int term_settc(EditLine *, int, const char **); +protected int term_gettc(EditLine *, int, char **); protected int term_telltc(EditLine *, int, const char **); protected int term_echotc(EditLine *, int, const char **); protected void term_writec(EditLine *, int); protected int term__putc(int); protected void term__flush(void); /* * Easy access macros */ #define EL_FLAGS (el)->el_term.t_flags #define EL_CAN_INSERT (EL_FLAGS & TERM_CAN_INSERT) #define EL_CAN_DELETE (EL_FLAGS & TERM_CAN_DELETE) #define EL_CAN_CEOL (EL_FLAGS & TERM_CAN_CEOL) #define EL_CAN_TAB (EL_FLAGS & TERM_CAN_TAB) #define EL_CAN_ME (EL_FLAGS & TERM_CAN_ME) #define EL_CAN_UP (EL_FLAGS & TERM_CAN_UP) #define EL_HAS_META (EL_FLAGS & TERM_HAS_META) #define EL_HAS_AUTO_MARGINS (EL_FLAGS & TERM_HAS_AUTO_MARGINS) #define EL_HAS_MAGIC_MARGINS (EL_FLAGS & TERM_HAS_MAGIC_MARGINS) #endif /* _h_el_term */