2005-09-20 23:26:39 +10:00
/** \file builtin_commandline.c Functions defining the commandline builtin
Functions used for implementing the commandline builtin .
*/
2006-08-11 11:18:35 +10:00
# include "config.h"
2005-09-20 23:26:39 +10:00
# include <stdlib.h>
# include <stdio.h>
# include <wchar.h>
# include <wctype.h>
# include <sys/types.h>
# include <termios.h>
# include <signal.h>
2006-02-28 23:17:16 +10:00
# include "fallback.h"
2005-09-20 23:26:39 +10:00
# include "util.h"
2006-02-28 23:17:16 +10:00
2006-01-21 00:27:21 +10:00
# include "wutil.h"
2005-09-20 23:26:39 +10:00
# include "builtin.h"
# include "common.h"
# include "wgetopt.h"
# include "reader.h"
# include "proc.h"
# include "parser.h"
# include "tokenizer.h"
# include "input_common.h"
# include "input.h"
2006-07-20 08:55:49 +10:00
2006-01-31 02:51:50 +10:00
# include "parse_util.h"
2005-09-20 23:26:39 +10:00
/**
Which part of the comandbuffer are we operating on
*/
enum
{
2005-12-15 23:59:02 +10:00
STRING_MODE = 1 , /**< Operate on entire buffer */
JOB_MODE , /**< Operate on job under cursor */
PROCESS_MODE , /**< Operate on process under cursor */
TOKEN_MODE /**< Operate on token under cursor */
2005-09-20 23:26:39 +10:00
}
;
/**
For text insertion , how should it be done
*/
enum
{
2005-12-15 23:59:02 +10:00
REPLACE_MODE = 1 , /**< Replace current text */
INSERT_MODE , /**< Insert at cursor position */
APPEND_MODE /**< Insert at end of current token/command/buffer */
2005-09-20 23:26:39 +10:00
}
;
2006-10-05 04:49:39 +10:00
static wchar_t * current_buffer = 0 ;
static int current_cursor_pos = - 1 ;
2006-01-31 02:51:50 +10:00
/**
Returns the current commandline buffer .
*/
2006-10-05 07:39:48 +10:00
static wchar_t * get_buffer ( )
2006-01-31 02:51:50 +10:00
{
2006-10-05 04:49:39 +10:00
return current_buffer ;
2006-01-31 02:51:50 +10:00
}
2006-06-17 23:07:08 +10:00
/**
Returns the position of the cursor
*/
2006-01-31 02:51:50 +10:00
static int get_cursor_pos ( )
{
2006-10-05 04:49:39 +10:00
return current_cursor_pos ;
2006-01-31 02:51:50 +10:00
}
2005-09-20 23:26:39 +10:00
2005-10-25 01:26:25 +10:00
/**
Replace / append / insert the selection with / at / after the specified string .
\ param begin beginning of selection
\ param end end of selection
\ param insert the string to insert
\ param append_mode can be one of REPLACE_MODE , INSERT_MODE or APPEND_MODE , affects the way the test update is performed
*/
2006-01-31 02:51:50 +10:00
static void replace_part ( const wchar_t * begin ,
const wchar_t * end ,
2005-09-20 23:26:39 +10:00
wchar_t * insert ,
int append_mode )
{
2006-01-31 02:51:50 +10:00
const wchar_t * buff = get_buffer ( ) ;
2005-09-20 23:26:39 +10:00
string_buffer_t out ;
2006-01-31 02:51:50 +10:00
int out_pos = get_cursor_pos ( ) ;
2005-09-20 23:26:39 +10:00
sb_init ( & out ) ;
sb_append_substring ( & out , buff , begin - buff ) ;
switch ( append_mode )
{
case REPLACE_MODE :
{
sb_append ( & out , insert ) ;
out_pos = wcslen ( insert ) + ( begin - buff ) ;
break ;
}
case APPEND_MODE :
{
sb_append_substring ( & out , begin , end - begin ) ;
sb_append ( & out , insert ) ;
break ;
}
case INSERT_MODE :
{
2006-01-31 02:51:50 +10:00
int cursor = get_cursor_pos ( ) - ( begin - buff ) ;
2005-09-20 23:26:39 +10:00
sb_append_substring ( & out , begin , cursor ) ;
sb_append ( & out , insert ) ;
sb_append_substring ( & out , begin + cursor , end - begin - cursor ) ;
out_pos + = wcslen ( insert ) ;
break ;
}
}
sb_append ( & out , end ) ;
reader_set_buffer ( ( wchar_t * ) out . buff , out_pos ) ;
sb_destroy ( & out ) ;
}
2005-10-25 01:26:25 +10:00
/**
Output the specified selection .
\ param begin start of selection
\ param end end of selection
\ param cut_at_cursor whether printing should stop at the surrent cursor position
\ param tokenize whether the string should be tokenized , printing one string token on every line and skipping non - string tokens
*/
2006-01-31 02:51:50 +10:00
static void write_part ( const wchar_t * begin ,
const wchar_t * end ,
2005-10-25 01:26:25 +10:00
int cut_at_cursor ,
int tokenize )
2005-09-20 23:26:39 +10:00
{
tokenizer tok ;
string_buffer_t out ;
wchar_t * buff ;
int pos ;
2006-01-31 02:51:50 +10:00
pos = get_cursor_pos ( ) - ( begin - get_buffer ( ) ) ;
2005-09-20 23:26:39 +10:00
if ( tokenize )
{
buff = wcsndup ( begin , end - begin ) ;
// fwprintf( stderr, L"Subshell: %ls, end char %lc\n", buff, *end );
sb_init ( & out ) ;
for ( tok_init ( & tok , buff , TOK_ACCEPT_UNFINISHED ) ;
tok_has_next ( & tok ) ;
tok_next ( & tok ) )
{
if ( ( cut_at_cursor ) & &
( tok_get_pos ( & tok ) + wcslen ( tok_last ( & tok ) ) > = pos ) )
break ;
// fwprintf( stderr, L"Next token %ls\n", tok_last( &tok ) );
switch ( tok_last_type ( & tok ) )
{
case TOK_STRING :
2005-10-01 04:28:26 +10:00
sb_append2 ( & out , tok_last ( & tok ) , L " \n " , ( void * ) 0 ) ;
2005-09-20 23:26:39 +10:00
break ;
}
}
if ( out . buff )
sb_append ( sb_out ,
( wchar_t * ) out . buff ) ;
free ( buff ) ;
tok_destroy ( & tok ) ;
sb_destroy ( & out ) ;
}
else
{
if ( cut_at_cursor )
{
end = begin + pos ;
}
sb_append_substring ( sb_out , begin , end - begin ) ;
sb_append ( sb_out , L " \n " ) ;
}
}
/**
The commandline builtin . It is used for specifying a new value for
the commandline .
*/
2006-06-13 23:43:28 +10:00
static int builtin_commandline ( wchar_t * * argv )
2005-09-20 23:26:39 +10:00
{
int buffer_part = 0 ;
int cut_at_cursor = 0 ;
int argc = builtin_count_args ( argv ) ;
int append_mode = 0 ;
int function_mode = 0 ;
int tokenize = 0 ;
2006-10-05 07:39:48 +10:00
int cursor_mode = 0 ;
wchar_t * begin , * end ;
2005-09-20 23:26:39 +10:00
2006-10-05 04:49:39 +10:00
current_buffer = ( wchar_t * ) builtin_complete_get_temporary_buffer ( ) ;
if ( current_buffer )
{
current_cursor_pos = wcslen ( current_buffer ) ;
}
else
{
current_buffer = reader_get_buffer ( ) ;
current_cursor_pos = reader_get_cursor_pos ( ) ;
}
2006-01-31 02:51:50 +10:00
if ( ! get_buffer ( ) )
2005-09-20 23:26:39 +10:00
{
sb_append2 ( sb_err ,
argv [ 0 ] ,
L " : Can not set commandline in non-interactive mode \n " ,
2005-10-01 04:28:26 +10:00
( void * ) 0 ) ;
2005-09-20 23:26:39 +10:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
woptind = 0 ;
while ( 1 )
{
const static struct woption
long_options [ ] =
{
{
L " append " , no_argument , 0 , ' a '
}
,
{
L " insert " , no_argument , 0 , ' i '
}
,
{
L " replace " , no_argument , 0 , ' r '
}
,
{
L " current-job " , no_argument , 0 , ' j '
}
,
{
L " current-process " , no_argument , 0 , ' p '
}
,
{
L " current-token " , no_argument , 0 , ' t '
}
,
{
L " current-buffer " , no_argument , 0 , ' b '
}
,
{
L " cut-at-cursor " , no_argument , 0 , ' c '
}
,
{
L " function " , no_argument , 0 , ' f '
}
,
{
L " tokenize " , no_argument , 0 , ' o '
}
,
2006-05-26 21:24:02 +10:00
{
L " help " , no_argument , 0 , ' h '
}
,
2006-10-05 04:49:39 +10:00
{
L " input " , required_argument , 0 , ' I '
}
,
2006-10-05 07:39:48 +10:00
{
L " cursor " , no_argument , 0 , ' C '
}
,
2005-09-20 23:26:39 +10:00
{
0 , 0 , 0 , 0
}
}
;
int opt_index = 0 ;
int opt = wgetopt_long ( argc ,
argv ,
2006-10-05 07:39:48 +10:00
L " aijpctwforhI:C " ,
2005-09-20 23:26:39 +10:00
long_options ,
& opt_index ) ;
if ( opt = = - 1 )
break ;
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 22:51:02 +10:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-09-20 23:26:39 +10:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
case L ' a ' :
append_mode = APPEND_MODE ;
break ;
case L ' i ' :
append_mode = INSERT_MODE ;
break ;
2005-12-15 20:19:01 +10:00
case L ' r ' :
append_mode = REPLACE_MODE ;
break ;
2005-09-20 23:26:39 +10:00
case ' c ' :
cut_at_cursor = 1 ;
break ;
case ' t ' :
buffer_part = TOKEN_MODE ;
break ;
case ' j ' :
buffer_part = JOB_MODE ;
break ;
case ' p ' :
buffer_part = PROCESS_MODE ;
break ;
case ' f ' :
function_mode = 1 ;
break ;
case ' o ' :
tokenize = 1 ;
break ;
2006-10-05 04:49:39 +10:00
case ' I ' :
current_buffer = woptarg ;
current_cursor_pos = wcslen ( woptarg ) ;
break ;
2006-10-05 07:39:48 +10:00
case ' C ' :
cursor_mode = 1 ;
break ;
2006-05-26 21:24:02 +10:00
case ' h ' :
builtin_print_help ( argv [ 0 ] , sb_out ) ;
return 0 ;
2005-09-20 23:26:39 +10:00
case L ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
}
if ( function_mode )
{
int i ;
/*
Check for invalid switch combinations
*/
2006-10-05 07:39:48 +10:00
if ( buffer_part | | cut_at_cursor | | append_mode | | tokenize | | cursor_mode )
2005-09-20 23:26:39 +10:00
{
2006-01-04 22:51:02 +10:00
sb_printf ( sb_err ,
BUILTIN_ERR_COMBO ,
argv [ 0 ] ) ;
2006-10-05 07:39:48 +10:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
2005-09-20 23:26:39 +10:00
return 1 ;
}
if ( argc = = woptind )
{
2006-01-04 22:51:02 +10:00
sb_printf ( sb_err ,
BUILTIN_ERR_MISSING ,
argv [ 0 ] ) ;
2005-09-20 23:26:39 +10:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
for ( i = woptind ; i < argc ; i + + )
{
wint_t c = input_get_code ( argv [ i ] ) ;
if ( c ! = - 1 )
{
/*
input_unreadch inserts the specified keypress or
readline function at the top of the stack of unused
keypresses
*/
input_unreadch ( c ) ;
}
else
{
2006-10-05 07:39:48 +10:00
sb_printf ( sb_err ,
_ ( L " %ls: Unknown readline function '%ls' \n " ) ,
argv [ 0 ] ,
argv [ i ] ) ;
2005-09-20 23:26:39 +10:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
}
return 0 ;
}
/*
Check for invalid switch combinations
*/
if ( argc - woptind > 1 )
{
sb_append2 ( sb_err ,
argv [ 0 ] ,
L " : Too many arguments \n " ,
2005-10-01 04:28:26 +10:00
( void * ) 0 ) ;
2005-09-20 23:26:39 +10:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
2006-10-05 07:39:48 +10:00
if ( ( buffer_part | | tokenize | | cut_at_cursor ) & & cursor_mode )
{
sb_printf ( sb_err ,
BUILTIN_ERR_COMBO ,
argv [ 0 ] ) ;
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
2005-09-20 23:26:39 +10:00
if ( ( tokenize | | cut_at_cursor ) & & ( argc - woptind ) )
{
2006-01-04 22:51:02 +10:00
sb_printf ( sb_err ,
BUILTIN_ERR_COMBO2 ,
argv [ 0 ] ,
L " --cut-at-cursor and --tokenize can not be used when setting the commandline " ) ;
2005-09-20 23:26:39 +10:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
if ( append_mode & & ! ( argc - woptind ) )
{
2006-01-04 22:51:02 +10:00
sb_printf ( sb_err ,
BUILTIN_ERR_COMBO2 ,
2005-09-20 23:26:39 +10:00
argv [ 0 ] ,
2006-01-04 22:51:02 +10:00
L " insertion mode switches can not be used when not in insertion mode " ) ;
2005-09-20 23:26:39 +10:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
/*
Set default modes
*/
if ( ! append_mode )
{
append_mode = REPLACE_MODE ;
}
if ( ! buffer_part )
{
buffer_part = STRING_MODE ;
}
2006-10-05 07:39:48 +10:00
if ( cursor_mode )
{
if ( argc - woptind )
{
wchar_t * endptr ;
int new_pos ;
errno = 0 ;
new_pos = wcstol ( argv [ woptind ] , & endptr , 10 ) ;
if ( * endptr | | errno )
{
sb_printf ( sb_err ,
BUILTIN_ERR_NOT_NUMBER ,
argv [ 0 ] ,
argv [ woptind ] ) ;
builtin_print_help ( argv [ 0 ] , sb_err ) ;
}
current_buffer = reader_get_buffer ( ) ;
new_pos = maxi ( 0 , mini ( new_pos , wcslen ( current_buffer ) ) ) ;
reader_set_buffer ( current_buffer , new_pos ) ;
return 0 ;
}
else
{
sb_printf ( sb_out , L " %d \n " , reader_get_cursor_pos ( ) ) ;
return 0 ;
}
2005-09-20 23:26:39 +10:00
2006-10-05 07:39:48 +10:00
}
2005-09-20 23:26:39 +10:00
2006-10-05 07:39:48 +10:00
2005-09-20 23:26:39 +10:00
switch ( buffer_part )
{
case STRING_MODE :
{
2006-10-05 04:49:39 +10:00
begin = get_buffer ( ) ;
2005-09-20 23:26:39 +10:00
end = begin + wcslen ( begin ) ;
break ;
}
case PROCESS_MODE :
{
2006-01-31 02:51:50 +10:00
parse_util_process_extent ( get_buffer ( ) ,
get_cursor_pos ( ) ,
& begin ,
& end ) ;
2005-09-20 23:26:39 +10:00
break ;
}
case JOB_MODE :
{
2006-01-31 02:51:50 +10:00
parse_util_job_extent ( get_buffer ( ) ,
get_cursor_pos ( ) ,
& begin ,
& end ) ;
2005-09-20 23:26:39 +10:00
break ;
}
case TOKEN_MODE :
{
2006-01-31 02:51:50 +10:00
parse_util_token_extent ( get_buffer ( ) ,
get_cursor_pos ( ) ,
& begin ,
& end ,
0 , 0 ) ;
2005-09-20 23:26:39 +10:00
break ;
}
}
switch ( argc - woptind )
{
case 0 :
{
write_part ( begin , end , cut_at_cursor , tokenize ) ;
break ;
}
case 1 :
{
replace_part ( begin , end , argv [ woptind ] , append_mode ) ;
break ;
}
}
return 0 ;
}