2005-09-20 23:26:39 +10:00
/** \file builtin_commandline.c Functions defining the commandline builtin
2012-11-18 11:23:22 +01:00
Functions used for implementing the commandline builtin .
2005-09-20 23:26:39 +10:00
*/
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
{
2012-11-18 16:30:30 -08: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
}
2012-11-18 16:30:30 -08:00
;
2005-09-20 23:26:39 +10:00
/**
For text insertion , how should it be done
*/
enum
{
2012-11-18 16:30:30 -08: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
}
2012-11-18 16:30:30 -08:00
;
2005-09-20 23:26:39 +10:00
2008-01-14 02:47:47 +10:00
/**
Pointer to what the commandline builtin considers to be the current
contents of the command line buffer .
*/
2012-02-06 00:57:43 -08:00
static const wchar_t * current_buffer = 0 ;
2008-01-14 02:47:47 +10:00
/**
What the commandline builtin considers to be the current cursor
position .
*/
2012-08-04 15:11:43 -07:00
static size_t current_cursor_pos = ( size_t ) ( - 1 ) ;
2006-10-05 04:49:39 +10:00
2006-01-31 02:51:50 +10:00
/**
Returns the current commandline buffer .
*/
2012-02-06 00:57:43 -08:00
static const wchar_t * get_buffer ( )
2006-01-31 02:51:50 +10:00
{
2012-11-18 16:30:30 -08: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
*/
2012-08-04 13:47:56 -07:00
static size_t get_cursor_pos ( )
2006-01-31 02:51:50 +10:00
{
2012-11-18 16:30:30 -08: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
*/
2012-11-18 16:30:30 -08:00
static void replace_part ( const wchar_t * begin ,
const wchar_t * end ,
const wchar_t * insert ,
int append_mode )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
const wchar_t * buff = get_buffer ( ) ;
size_t out_pos = get_cursor_pos ( ) ;
2012-11-18 11:23:22 +01:00
2012-02-22 11:07:34 -08:00
wcstring out ;
2005-09-20 23:26:39 +10:00
2012-02-22 11:07:34 -08:00
out . append ( buff , begin - buff ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
switch ( append_mode )
{
2012-11-19 00:31:03 -08:00
case REPLACE_MODE :
{
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
out . append ( insert ) ;
out_pos = wcslen ( insert ) + ( begin - buff ) ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
}
case APPEND_MODE :
{
out . append ( begin , end - begin ) ;
out . append ( insert ) ;
break ;
}
case INSERT_MODE :
{
long cursor = get_cursor_pos ( ) - ( begin - buff ) ;
out . append ( begin , cursor ) ;
out . append ( insert ) ;
out . append ( begin + cursor , end - begin - cursor ) ;
out_pos + = wcslen ( insert ) ;
break ;
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
out . append ( end ) ;
reader_set_buffer ( out , out_pos ) ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 11:23:22 +01:00
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
*/
2012-11-18 16:30:30 -08:00
static void write_part ( const wchar_t * begin ,
const wchar_t * end ,
int cut_at_cursor ,
int tokenize )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
wcstring out ;
wchar_t * buff ;
size_t pos ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
pos = get_cursor_pos ( ) - ( begin - get_buffer ( ) ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( tokenize )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
buff = wcsndup ( begin , end - begin ) ;
// fwprintf( stderr, L"Subshell: %ls, end char %lc\n", buff, *end );
out . clear ( ) ;
2012-11-21 17:48:35 -08:00
tokenizer_t tok ( buff , TOK_ACCEPT_UNFINISHED ) ;
2012-11-22 01:09:07 -08:00
for ( ; tok_has_next ( & tok ) ; tok_next ( & tok ) )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
if ( ( cut_at_cursor ) & &
( tok_get_pos ( & tok ) + wcslen ( tok_last ( & tok ) ) > = pos ) )
break ;
switch ( tok_last_type ( & tok ) )
{
2012-11-19 00:31:03 -08:00
case TOK_STRING :
{
out . append ( escape_string ( tok_last ( & tok ) , UNESCAPE_INCOMPLETE ) ) ;
out . push_back ( L ' \n ' ) ;
break ;
}
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
}
2012-02-22 12:00:02 -08:00
stdout_buffer . append ( out ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
free ( buff ) ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
else
{
if ( cut_at_cursor )
{
end = begin + pos ;
}
2012-11-18 11:23:22 +01:00
// debug( 0, L"woot2 %ls -> %ls", buff, esc );
2007-01-19 02:27:00 +10:00
2012-04-18 13:41:39 -07:00
stdout_buffer . append ( begin , end - begin ) ;
2012-02-22 10:51:06 -08:00
stdout_buffer . append ( L " \n " ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
}
2005-09-20 23:26:39 +10:00
}
/**
The commandline builtin . It is used for specifying a new value for
the commandline .
*/
2012-11-18 16:30:30 -08:00
static int builtin_commandline ( parser_t & parser , wchar_t * * argv )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
int buffer_part = 0 ;
int cut_at_cursor = 0 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
int argc = builtin_count_args ( argv ) ;
int append_mode = 0 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
int function_mode = 0 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
int tokenize = 0 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
int cursor_mode = 0 ;
int line_mode = 0 ;
int search_mode = 0 ;
const wchar_t * begin , * end ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
current_buffer = ( wchar_t * ) builtin_complete_get_temporary_buffer ( ) ;
if ( current_buffer )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
current_cursor_pos = wcslen ( current_buffer ) ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
else
{
current_buffer = reader_get_buffer ( ) ;
current_cursor_pos = reader_get_cursor_pos ( ) ;
}
if ( ! get_buffer ( ) )
{
if ( is_interactive_session )
{
/*
Prompt change requested while we don ' t have
a prompt , most probably while reading the
init files . Just ignore it .
*/
return 1 ;
}
2012-11-18 11:23:22 +01:00
2012-02-22 10:51:06 -08:00
stderr_buffer . append ( argv [ 0 ] ) ;
stderr_buffer . append ( L " : Can not set commandline in non-interactive mode \n " ) ;
2012-11-18 16:30:30 -08:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
return 1 ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
woptind = 0 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
while ( 1 )
{
static const struct woption
long_options [ ] =
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
{
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 '
}
,
{
L " help " , no_argument , 0 , ' h '
}
,
{
L " input " , required_argument , 0 , ' I '
}
,
{
L " cursor " , no_argument , 0 , ' C '
}
,
{
L " line " , no_argument , 0 , ' L '
}
,
{
L " search-mode " , no_argument , 0 , ' S '
}
,
{
0 , 0 , 0 , 0
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
;
int opt_index = 0 ;
int opt = wgetopt_long ( argc ,
argv ,
L " abijpctwforhI:CLS " ,
long_options ,
& opt_index ) ;
if ( opt = = - 1 )
break ;
switch ( opt )
2012-11-18 11:23:22 +01:00
{
2012-11-19 00:31:03 -08:00
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
append_format ( stderr_buffer ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
return 1 ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case L ' a ' :
append_mode = APPEND_MODE ;
break ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case L ' b ' :
buffer_part = STRING_MODE ;
break ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case L ' i ' :
append_mode = INSERT_MODE ;
break ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case L ' r ' :
append_mode = REPLACE_MODE ;
break ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case ' c ' :
cut_at_cursor = 1 ;
break ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case ' t ' :
buffer_part = TOKEN_MODE ;
break ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case ' j ' :
buffer_part = JOB_MODE ;
break ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case ' p ' :
buffer_part = PROCESS_MODE ;
break ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case ' f ' :
function_mode = 1 ;
break ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case ' o ' :
tokenize = 1 ;
break ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case ' I ' :
current_buffer = woptarg ;
current_cursor_pos = wcslen ( woptarg ) ;
break ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case ' C ' :
cursor_mode = 1 ;
break ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case ' L ' :
line_mode = 1 ;
break ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case ' S ' :
search_mode = 1 ;
break ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case ' h ' :
builtin_print_help ( parser , argv [ 0 ] , stdout_buffer ) ;
return 0 ;
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case L ' ? ' :
builtin_unknown_option ( parser , argv [ 0 ] , argv [ woptind - 1 ] ) ;
return 1 ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
}
if ( function_mode )
{
int i ;
/*
Check for invalid switch combinations
*/
if ( buffer_part | | cut_at_cursor | | append_mode | | tokenize | | cursor_mode | | line_mode | | search_mode )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
append_format ( stderr_buffer ,
BUILTIN_ERR_COMBO ,
argv [ 0 ] ) ;
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
return 1 ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
if ( argc = = woptind )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
append_format ( stderr_buffer ,
BUILTIN_ERR_MISSING ,
argv [ 0 ] ) ;
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
return 1 ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
for ( i = woptind ; i < argc ; i + + )
2012-11-18 11:23:22 +01:00
{
2013-04-03 18:27:18 -07:00
wchar_t c = input_function_get_code ( argv [ i ] ) ;
if ( c ! = ( wchar_t ) ( - 1 ) )
2012-11-18 16:30:30 -08:00
{
/*
input_unreadch inserts the specified keypress or
readline function at the top of the stack of unused
keypresses
*/
input_unreadch ( c ) ;
}
else
{
append_format ( stderr_buffer ,
_ ( L " %ls: Unknown input function '%ls' \n " ) ,
argv [ 0 ] ,
argv [ i ] ) ;
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
return 1 ;
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
return 0 ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
/*
Check for invalid switch combinations
*/
if ( ( search_mode | | line_mode | | cursor_mode ) & & ( argc - woptind > 1 ) )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
append_format ( stderr_buffer ,
argv [ 0 ] ,
L " : Too many arguments \n " ,
NULL ) ;
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2012-11-18 11:23:22 +01:00
return 1 ;
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( ( buffer_part | | tokenize | | cut_at_cursor ) & & ( cursor_mode | | line_mode | | search_mode ) )
{
append_format ( stderr_buffer ,
BUILTIN_ERR_COMBO ,
argv [ 0 ] ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
return 1 ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( ( tokenize | | cut_at_cursor ) & & ( argc - woptind ) )
{
append_format ( stderr_buffer ,
BUILTIN_ERR_COMBO2 ,
argv [ 0 ] ,
L " --cut-at-cursor and --tokenize can not be used when setting the commandline " ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
return 1 ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( append_mode & & ! ( argc - woptind ) )
{
append_format ( stderr_buffer ,
BUILTIN_ERR_COMBO2 ,
argv [ 0 ] ,
L " insertion mode switches can not be used when not in insertion mode " ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2012-11-18 11:23:22 +01:00
return 1 ;
}
/*
2012-11-18 16:30:30 -08:00
Set default modes
2012-11-18 11:23:22 +01:00
*/
2012-11-18 16:30:30 -08:00
if ( ! append_mode )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
append_mode = REPLACE_MODE ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
if ( ! buffer_part )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
buffer_part = STRING_MODE ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
if ( cursor_mode )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
if ( argc - woptind )
{
wchar_t * endptr ;
long new_pos ;
errno = 0 ;
new_pos = wcstol ( argv [ woptind ] , & endptr , 10 ) ;
if ( * endptr | | errno )
{
append_format ( stderr_buffer ,
BUILTIN_ERR_NOT_NUMBER ,
argv [ 0 ] ,
argv [ woptind ] ) ;
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
}
current_buffer = reader_get_buffer ( ) ;
new_pos = maxi ( 0L , mini ( new_pos , ( long ) wcslen ( current_buffer ) ) ) ;
reader_set_buffer ( current_buffer , ( size_t ) new_pos ) ;
return 0 ;
}
else
{
append_format ( stdout_buffer , L " %lu \n " , ( unsigned long ) reader_get_cursor_pos ( ) ) ;
return 0 ;
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
if ( line_mode )
{
size_t pos = reader_get_cursor_pos ( ) ;
const wchar_t * buff = reader_get_buffer ( ) ;
append_format ( stdout_buffer , L " %lu \n " , ( unsigned long ) parse_util_lineno ( buff , pos ) ) ;
return 0 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( search_mode )
{
return ! reader_search_mode ( ) ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
switch ( buffer_part )
{
2012-11-19 00:31:03 -08:00
case STRING_MODE :
{
begin = get_buffer ( ) ;
end = begin + wcslen ( begin ) ;
break ;
}
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case PROCESS_MODE :
{
parse_util_process_extent ( get_buffer ( ) ,
get_cursor_pos ( ) ,
& begin ,
& end ) ;
break ;
}
case JOB_MODE :
{
parse_util_job_extent ( get_buffer ( ) ,
2012-11-18 16:30:30 -08:00
get_cursor_pos ( ) ,
& begin ,
& end ) ;
2012-11-19 00:31:03 -08:00
break ;
}
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case TOKEN_MODE :
{
parse_util_token_extent ( get_buffer ( ) ,
get_cursor_pos ( ) ,
& begin ,
& end ,
0 , 0 ) ;
break ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
switch ( argc - woptind )
{
2012-11-19 00:31:03 -08:00
case 0 :
{
write_part ( begin , end , cut_at_cursor , tokenize ) ;
break ;
}
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case 1 :
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
replace_part ( begin , end , argv [ woptind ] , append_mode ) ;
break ;
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
default :
{
wcstring sb = argv [ woptind ] ;
int i ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
for ( i = woptind + 1 ; i < argc ; i + + )
{
sb . push_back ( L ' \n ' ) ;
sb . append ( argv [ i ] ) ;
}
replace_part ( begin , end , sb . c_str ( ) , append_mode ) ;
break ;
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
return 0 ;
2005-09-20 23:26:39 +10:00
}