aboutsummaryrefslogtreecommitdiffhomepage
path: root/builtin_commandline.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin_commandline.c')
-rw-r--r--builtin_commandline.c461
1 files changed, 461 insertions, 0 deletions
diff --git a/builtin_commandline.c b/builtin_commandline.c
new file mode 100644
index 00000000..8b915868
--- /dev/null
+++ b/builtin_commandline.c
@@ -0,0 +1,461 @@
+/** \file builtin_commandline.c Functions defining the commandline builtin
+
+Functions used for implementing the commandline builtin.
+
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <wctype.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <signal.h>
+
+#include "config.h"
+#include "util.h"
+#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"
+
+/**
+ Which part of the comandbuffer are we operating on
+*/
+enum
+{
+ 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
+}
+ ;
+
+/**
+ For text insertion, how should it be done
+*/
+enum
+{
+ REPLACE_MODE=1, // Replace current text
+ INSERT_MODE, // Insert at cursor position
+ APPEND_MODE // Insert at end of current token/command/buffer
+}
+ ;
+
+
+static void replace_part( wchar_t *begin,
+ wchar_t *end,
+ wchar_t *insert,
+ int append_mode )
+{
+ wchar_t *buff = reader_get_buffer();
+ string_buffer_t out;
+ int out_pos=reader_get_cursor_pos();
+
+ sb_init( &out );
+
+// wchar_t *tmp = wcsndup( begin, end-begin );
+
+// fwprintf( stderr, L"Commandline '%ls', current command '%ls'\n", reader_get_buffer(), tmp );
+
+ 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:
+ {
+ int cursor = reader_get_cursor_pos() -(begin-buff);
+ 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 );
+}
+
+void write_part( wchar_t *begin,
+ wchar_t *end,
+ int cut_at_cursor,
+ int tokenize )
+{
+ tokenizer tok;
+ string_buffer_t out;
+ wchar_t *buff;
+ int pos;
+
+ pos = reader_get_cursor_pos()-(begin-reader_get_buffer());
+
+ 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:
+ sb_append2( &out, tok_last( &tok), L"\n", 0 );
+ 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.
+*/
+int builtin_commandline( wchar_t **argv )
+{
+
+ 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;
+
+ if( !reader_get_buffer() )
+ {
+ sb_append2( sb_err,
+ argv[0],
+ L": Can not set commandline in non-interactive mode\n",
+ 0 );
+ 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'
+ }
+ ,
+ {
+ 0, 0, 0, 0
+ }
+ }
+ ;
+
+ int opt_index = 0;
+
+ int opt = wgetopt_long( argc,
+ argv,
+ L"aijpctwfo",
+ long_options,
+ &opt_index );
+ if( opt == -1 )
+ break;
+
+ switch( opt )
+ {
+ case 0:
+ if(long_options[opt_index].flag != 0)
+ break;
+ sb_append2( sb_err,
+ argv[0],
+ BUILTIN_ERR_UNKNOWN,
+ L" ",
+ long_options[opt_index].name,
+ L"\n",
+ 0 );
+ 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;
+
+ 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;
+
+ case L'?':
+ builtin_print_help( argv[0], sb_err );
+ return 1;
+ }
+ }
+
+ if( function_mode )
+ {
+ int i;
+
+ /*
+ Check for invalid switch combinations
+ */
+ if( buffer_part || cut_at_cursor || append_mode || tokenize )
+ {
+ sb_append2(sb_err,
+ argv[0],
+ BUILTIN_ERR_COMBO,
+ L"\n",
+ parser_current_line(),
+ L"\n",
+ 0);
+ return 1;
+ }
+
+
+ if( argc == woptind )
+ {
+ sb_append2( sb_err,
+ argv[0],
+ BUILTIN_ERR_MISSING,
+ L"\n",
+ parser_current_line(),
+ L"\n",
+ 0 );
+ 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 )
+ {
+// fwprintf( stderr, L"Add function %ls (%d)\n", argv[i], c );
+ /*
+ input_unreadch inserts the specified keypress or
+ readline function at the top of the stack of unused
+ keypresses
+ */
+ input_unreadch(c);
+ }
+ else
+ {
+// fwprintf( stderr, L"BLUR %ls %d\n", argv[i], c );
+ sb_append2( sb_err,
+ argv[0],
+ L": Unknown readline function '",
+ argv[i],
+ L"'\n",
+ parser_current_line(),
+ L"\n",
+ 0 );
+ 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",
+ 0 );
+ builtin_print_help( argv[0], sb_err );
+ return 1;
+ }
+
+ if( (tokenize || cut_at_cursor) && (argc-woptind) )
+ {
+
+ sb_append2( sb_err,
+ argv[0],
+ BUILTIN_ERR_COMBO,
+ L",\n --cut-at-cursor and --tokenize can not be used when setting the commandline",
+ 0 );
+ builtin_print_help( argv[0], sb_err );
+ return 1;
+ }
+
+ if( append_mode && !(argc-woptind) )
+ {
+ sb_append2( sb_err,
+ argv[0],
+ BUILTIN_ERR_COMBO,
+ L",\n insertion mode switches can not be used when not in insertion mode",
+ 0 );
+ 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;
+ }
+
+ wchar_t *begin, *end;
+
+ switch( buffer_part )
+ {
+ case STRING_MODE:
+ {
+ begin = reader_get_buffer();
+ end = begin+wcslen(begin);
+ break;
+ }
+
+ case PROCESS_MODE:
+ {
+ reader_current_process_extent( &begin, &end );
+ break;
+ }
+
+ case JOB_MODE:
+ {
+ reader_current_job_extent( &begin, &end );
+ break;
+ }
+
+ case TOKEN_MODE:
+ {
+ reader_current_token_extent( &begin, &end, 0, 0 );
+ 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;
+}