diff options
Diffstat (limited to 'expand.cpp')
-rw-r--r-- | expand.cpp | 1560 |
1 files changed, 780 insertions, 780 deletions
@@ -1,7 +1,7 @@ /**\file expand.c String expansion functions. These functions perform several kinds of -parameter expansion. +parameter expansion. */ @@ -128,27 +128,27 @@ static void remove_internal_separator( wcstring &s, bool conv ); int expand_is_clean( const wchar_t *in ) { - const wchar_t * str = in; + const wchar_t * str = in; - CHECK( in, 1 ); + CHECK( in, 1 ); - /* - Test characters that have a special meaning in the first character position - */ - if( wcschr( UNCLEAN_FIRST, *str ) ) - return 0; + /* + Test characters that have a special meaning in the first character position + */ + if( wcschr( UNCLEAN_FIRST, *str ) ) + return 0; - /* - Test characters that have a special meaning in any character position - */ - while( *str ) - { - if( wcschr( UNCLEAN, *str ) ) - return 0; - str++; - } + /* + Test characters that have a special meaning in any character position + */ + while( *str ) + { + if( wcschr( UNCLEAN, *str ) ) + return 0; + str++; + } - return 1; + return 1; } /** @@ -156,9 +156,9 @@ int expand_is_clean( const wchar_t *in ) */ static env_var_t expand_var(const wchar_t *in) { - if( !in ) - return env_var_t::missing_var(); - return env_get_string( in ); + if( !in ) + return env_var_t::missing_var(); + return env_get_string( in ); } /** @@ -167,22 +167,22 @@ static env_var_t expand_var(const wchar_t *in) */ static int is_quotable( const wchar_t *str ) { - switch( *str ) - { - case 0: - return 1; - - case L'\n': - case L'\t': - case L'\r': - case L'\b': - case L'\x1b': - return 0; - - default: - return is_quotable(str+1); - } - return 0; + switch( *str ) + { + case 0: + return 1; + + case L'\n': + case L'\t': + case L'\r': + case L'\b': + case L'\x1b': + return 0; + + default: + return is_quotable(str+1); + } + return 0; } @@ -193,55 +193,55 @@ static int is_quotable(const wcstring &str) { wcstring expand_escape_variable( const wcstring &in ) { - wcstring_list_t lst; - wcstring buff; + wcstring_list_t lst; + wcstring buff; - tokenize_variable_array( in, lst ); + tokenize_variable_array( in, lst ); - switch( lst.size() ) - { - case 0: - buff.append(L"''"); - break; - - case 1: - { + switch( lst.size() ) + { + case 0: + buff.append(L"''"); + break; + + case 1: + { const wcstring &el = lst.at(0); - if( el.find(L' ') != wcstring::npos && is_quotable( el ) ) - { + if( el.find(L' ') != wcstring::npos && is_quotable( el ) ) + { buff.append(L"'"); buff.append(el); buff.append(L"'"); - } - else - { + } + else + { buff.append(escape_string(el, 1)); - } - break; - } - default: - { - for( size_t j=0; j<lst.size(); j++ ) - { - const wcstring &el = lst.at(j); - if( j ) - buff.append(L" " ); - - if( is_quotable( el ) ) - { + } + break; + } + default: + { + for( size_t j=0; j<lst.size(); j++ ) + { + const wcstring &el = lst.at(j); + if( j ) + buff.append(L" " ); + + if( is_quotable( el ) ) + { buff.append(L"'"); buff.append(el); buff.append(L"'"); - } - else - { + } + else + { buff.append(escape_string(el, 1)); - } - } - } - } - return buff; + } + } + } + } + return buff; } /** @@ -249,14 +249,14 @@ wcstring expand_escape_variable( const wcstring &in ) */ static int iswnumeric( const wchar_t *n ) { - for( ; *n; n++ ) - { - if( *n < L'0' || *n > L'9' ) - { - return 0; - } - } - return 1; + for( ; *n; n++ ) + { + if( *n < L'0' || *n > L'9' ) + { + return 0; + } + } + return 1; } /** @@ -264,21 +264,21 @@ static int iswnumeric( const wchar_t *n ) cmd */ static bool match_pid( const wcstring &cmd, - const wchar_t *proc, - int flags, - size_t *offset) + const wchar_t *proc, + int flags, + size_t *offset) { - /* Test for a direct match. If the proc string is empty (e.g. the user tries to complete against %), then return an offset pointing at the base command. That ensures that you don't see a bunch of dumb paths when completing against all processes. */ - if( proc[0] != L'\0' && wcsncmp( cmd.c_str(), proc, wcslen( proc ) ) == 0 ) - { - if( offset ) - *offset = 0; - return true; - } - + /* Test for a direct match. If the proc string is empty (e.g. the user tries to complete against %), then return an offset pointing at the base command. That ensures that you don't see a bunch of dumb paths when completing against all processes. */ + if( proc[0] != L'\0' && wcsncmp( cmd.c_str(), proc, wcslen( proc ) ) == 0 ) + { + if( offset ) + *offset = 0; + return true; + } + /* Get the command to match against. We're only interested in the last path component. */ const wcstring base_cmd = wbasename(cmd); - + bool result = string_prefixes_string(proc, base_cmd); if (result) { @@ -297,9 +297,9 @@ static bool match_pid( const wcstring &cmd, class process_iterator_t { std::vector<pid_t> pids; size_t idx; - + wcstring name_for_pid(pid_t pid); - + public: process_iterator_t(); bool next_process(wcstring *str, pid_t *pid); @@ -311,30 +311,30 @@ wcstring process_iterator_t::name_for_pid(pid_t pid) int mib[4], maxarg = 0, numArgs = 0; size_t size = 0; char *args = NULL, *stringPtr = NULL; - + mib[0] = CTL_KERN; mib[1] = KERN_ARGMAX; - + size = sizeof(maxarg); if (sysctl(mib, 2, &maxarg, &size, NULL, 0) == -1) { return result; } - + args = (char *)malloc( maxarg ); if ( args == NULL ) { return result; } - + mib[0] = CTL_KERN; mib[1] = KERN_PROCARGS2; mib[2] = pid; - + size = (size_t)maxarg; if ( sysctl(mib, 3, args, &size, NULL, 0) == -1 ) { free( args ); return result;; } - + memcpy( &numArgs, args, sizeof(numArgs) ); stringPtr = args + sizeof(numArgs); result = str2wcstring(stringPtr); @@ -374,8 +374,8 @@ process_iterator_t::process_iterator_t() : idx(0) // Declaring name as const requires us to cast it when passing it to // sysctl because the prototype doesn't include the const modifier. size_t length; - - + + // We start by calling sysctl with result == NULL and length == 0. // That will succeed, and set length to the appropriate length. // We then allocate a buffer of that size and call sysctl again @@ -385,14 +385,14 @@ process_iterator_t::process_iterator_t() : idx(0) // is necessary because the ENOMEM failure case sets length to // the amount of data returned, not the amount of data that // could have been returned. - + result = NULL; done = false; do { assert(result == NULL); - + // Call sysctl with a NULL buffer. - + length = 0; err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1, NULL, &length, @@ -400,20 +400,20 @@ process_iterator_t::process_iterator_t() : idx(0) if (err == -1) { err = errno; } - + // Allocate an appropriately sized buffer based on the results // from the previous call. - + if (err == 0) { result = (struct kinfo_proc *)malloc(length); if (result == NULL) { err = ENOMEM; } } - + // Call sysctl again with the new buffer. If we get an ENOMEM // error, toss away our buffer and start again. - + if (err == 0) { err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1, result, &length, @@ -431,16 +431,16 @@ process_iterator_t::process_iterator_t() : idx(0) } } } while (err == 0 && ! done); - + // Clean up and establish post conditions. if (err == 0 && result != NULL) { for (size_t idx = 0; idx < length / sizeof(struct kinfo_proc); idx++) pids.push_back(result[idx].kp_proc.p_pid); } - + if (result) - free(result); + free(result); } #else @@ -448,11 +448,11 @@ process_iterator_t::process_iterator_t() : idx(0) /* /proc style process completions */ class process_iterator_t { DIR *dir; - + public: process_iterator_t(); ~process_iterator_t(); - + bool next_process(wcstring *out_str, pid_t *out_pid); }; @@ -476,30 +476,30 @@ bool process_iterator_t::next_process(wcstring *out_str, pid_t *out_pid) wcstring name; if (! dir || ! wreaddir(dir, name)) break; - - if (!iswnumeric(name.c_str())) - continue; - + + if (!iswnumeric(name.c_str())) + continue; + wcstring path = wcstring(L"/proc/") + name; struct stat buf; - if (wstat(path, &buf)) - continue; + if (wstat(path, &buf)) + continue; + + if( buf.st_uid != getuid() ) + continue; - if( buf.st_uid != getuid() ) - continue; - /* remember the pid */ pid = fish_wcstoi(name.c_str(), NULL, 10); - + /* the 'cmdline' file exists, it should contain the commandline */ FILE *cmdfile; if ((cmdfile=wfopen(path + L"/cmdline", "r"))) { wcstring full_command_line; - signal_block(); - fgetws2(&full_command_line, cmdfile); - signal_unblock(); - + signal_block(); + fgetws2(&full_command_line, cmdfile); + signal_unblock(); + /* The command line needs to be escaped */ wchar_t *first_arg = tok_first( full_command_line.c_str() ); if (first_arg) @@ -522,7 +522,7 @@ bool process_iterator_t::next_process(wcstring *out_str, pid_t *out_pid) if (cmdfile) fclose(cmdfile); } - + bool result = ! cmd.empty(); if (result) { @@ -562,11 +562,11 @@ std::vector<wcstring> expand_get_all_process_names(void) */ static int find_process( const wchar_t *proc, - expand_flags_t flags, - std::vector<completion_t> &out ) + expand_flags_t flags, + std::vector<completion_t> &out ) { - int found = 0; - + int found = 0; + if (! (flags & EXPAND_SKIP_JOBS)) { ASSERT_IS_MAIN_THREAD(); @@ -592,7 +592,7 @@ static int find_process( const wchar_t *proc, if( wcsncmp( proc, jid, wcslen(proc ) )==0 ) { wcstring desc_buff = format_string(COMPLETE_JOB_DESC_VAL, j->command_wcstr()); - append_completion( out, + append_completion( out, jid+wcslen(proc), desc_buff, 0 ); @@ -605,7 +605,7 @@ static int find_process( const wchar_t *proc, int jid; wchar_t *end; - + errno = 0; jid = fish_wcstoi( proc, &end, 10 ); if( jid > 0 && !errno && !*end ) @@ -627,16 +627,16 @@ static int find_process( const wchar_t *proc, job_iterator_t jobs; while ((j = jobs.next())) { - + if( j->command_is_empty() ) continue; - + size_t offset; if( match_pid( j->command(), proc, flags, &offset ) ) { if( flags & ACCEPT_INCOMPLETE ) { - append_completion( out, + append_completion( out, j->command_wcstr() + offset + wcslen(proc), COMPLETE_JOB_DESC, 0 ); @@ -664,13 +664,13 @@ static int find_process( const wchar_t *proc, { if( p->actual_cmd.empty() ) continue; - + size_t offset; if( match_pid( p->actual_cmd, proc, flags, &offset ) ) { if( flags & ACCEPT_INCOMPLETE ) { - append_completion( out, + append_completion( out, wcstring(p->actual_cmd, offset + wcslen(proc)), COMPLETE_CHILD_PROCESS_DESC, 0 ); @@ -704,7 +704,7 @@ static int find_process( const wchar_t *proc, { if( flags & ACCEPT_INCOMPLETE ) { - append_completion( out, + append_completion( out, process_name.c_str() + offset + wcslen(proc), COMPLETE_PROCESS_DESC, 0 ); @@ -716,162 +716,162 @@ static int find_process( const wchar_t *proc, } } - return 1; + return 1; } /** Process id expansion */ static int expand_pid( const wcstring &instr_with_sep, - expand_flags_t flags, - std::vector<completion_t> &out ) + expand_flags_t flags, + std::vector<completion_t> &out ) { - + /* expand_string calls us with internal separators in instr...sigh */ wcstring instr = instr_with_sep; remove_internal_separator(instr, false); - - if( instr.empty() || instr.at(0) != PROCESS_EXPAND ) - { + + if( instr.empty() || instr.at(0) != PROCESS_EXPAND ) + { append_completion(out, instr); - return 1; - } - + return 1; + } + const wchar_t * const in = instr.c_str(); - if( flags & ACCEPT_INCOMPLETE ) - { - if( wcsncmp( in+1, SELF_STR, wcslen(in+1) )==0 ) - { - append_completion( out, - SELF_STR+wcslen(in+1), - COMPLETE_SELF_DESC, - 0 ); - } - else if( wcsncmp( in+1, LAST_STR, wcslen(in+1) )==0 ) - { - append_completion( out, - LAST_STR+wcslen(in+1), - COMPLETE_LAST_DESC, - 0 ); - } - } - else - { - if( wcscmp( (in+1), SELF_STR )==0 ) - { + if( flags & ACCEPT_INCOMPLETE ) + { + if( wcsncmp( in+1, SELF_STR, wcslen(in+1) )==0 ) + { + append_completion( out, + SELF_STR+wcslen(in+1), + COMPLETE_SELF_DESC, + 0 ); + } + else if( wcsncmp( in+1, LAST_STR, wcslen(in+1) )==0 ) + { + append_completion( out, + LAST_STR+wcslen(in+1), + COMPLETE_LAST_DESC, + 0 ); + } + } + else + { + if( wcscmp( (in+1), SELF_STR )==0 ) + { append_completion(out, to_string<long>(getpid())); - return 1; - } - if( wcscmp( (in+1), LAST_STR )==0 ) - { - if( proc_last_bg_pid > 0 ) - { + return 1; + } + if( wcscmp( (in+1), LAST_STR )==0 ) + { + if( proc_last_bg_pid > 0 ) + { append_completion(out, to_string<long>(proc_last_bg_pid)); - } + } - return 1; - } - } + return 1; + } + } - size_t prev = out.size(); - if( !find_process( in+1, flags, out ) ) - return 0; + size_t prev = out.size(); + if( !find_process( in+1, flags, out ) ) + return 0; - if( prev == out.size() ) - { - if( ! (flags & ACCEPT_INCOMPLETE) ) - { - return 0; - } - } + if( prev == out.size() ) + { + if( ! (flags & ACCEPT_INCOMPLETE) ) + { + return 0; + } + } - return 1; + return 1; } void expand_variable_error( parser_t &parser, const wchar_t *token, size_t token_pos, int error_pos ) { - size_t stop_pos = token_pos+1; - - switch( token[stop_pos] ) - { - case BRACKET_BEGIN: - { - wchar_t *cpy = wcsdup( token ); - *(cpy+token_pos)=0; - wchar_t *name = &cpy[stop_pos+1]; - wchar_t *end = wcschr( name, BRACKET_END ); - wchar_t *post; - int is_var=0; - if( end ) - { - post = end+1; - *end = 0; - - if( !wcsvarname( name ) ) - { - is_var = 1; - } - } - - if( is_var ) - { - parser.error( SYNTAX_ERROR, - error_pos, - COMPLETE_VAR_BRACKET_DESC, - cpy, - name, - post ); - } - else - { - parser.error( SYNTAX_ERROR, - error_pos, - COMPLETE_VAR_BRACKET_DESC, - L"", - L"VARIABLE", - L"" ); - } - free( cpy ); - - break; - } - - case INTERNAL_SEPARATOR: - { - parser.error( SYNTAX_ERROR, - error_pos, - COMPLETE_VAR_PARAN_DESC ); - break; - } - - case 0: - { - parser.error( SYNTAX_ERROR, - error_pos, - COMPLETE_VAR_NULL_DESC ); - break; - } - - default: - { + size_t stop_pos = token_pos+1; + + switch( token[stop_pos] ) + { + case BRACKET_BEGIN: + { + wchar_t *cpy = wcsdup( token ); + *(cpy+token_pos)=0; + wchar_t *name = &cpy[stop_pos+1]; + wchar_t *end = wcschr( name, BRACKET_END ); + wchar_t *post; + int is_var=0; + if( end ) + { + post = end+1; + *end = 0; + + if( !wcsvarname( name ) ) + { + is_var = 1; + } + } + + if( is_var ) + { + parser.error( SYNTAX_ERROR, + error_pos, + COMPLETE_VAR_BRACKET_DESC, + cpy, + name, + post ); + } + else + { + parser.error( SYNTAX_ERROR, + error_pos, + COMPLETE_VAR_BRACKET_DESC, + L"", + L"VARIABLE", + L"" ); + } + free( cpy ); + + break; + } + + case INTERNAL_SEPARATOR: + { + parser.error( SYNTAX_ERROR, + error_pos, + COMPLETE_VAR_PARAN_DESC ); + break; + } + + case 0: + { + parser.error( SYNTAX_ERROR, + error_pos, + COMPLETE_VAR_NULL_DESC ); + break; + } + + default: + { wchar_t token_stop_char = token[stop_pos]; // Unescape (see http://github.com/fish-shell/fish-shell/issues/50) if (token_stop_char == ANY_CHAR) token_stop_char = L'?'; else if (token_stop_char == ANY_STRING || token_stop_char == ANY_STRING_RECURSIVE) token_stop_char = L'*'; - - parser.error( SYNTAX_ERROR, - error_pos, - (token_stop_char == L'?' ? COMPLETE_YOU_WANT_STATUS : COMPLETE_VAR_DESC), - token_stop_char ); - break; - } - } + + parser.error( SYNTAX_ERROR, + error_pos, + (token_stop_char == L'?' ? COMPLETE_YOU_WANT_STATUS : COMPLETE_VAR_DESC), + token_stop_char ); + break; + } + } } /** @@ -879,73 +879,73 @@ void expand_variable_error( parser_t &parser, const wchar_t *token, size_t token */ static int parse_slice( const wchar_t *in, wchar_t **end_ptr, std::vector<long> &idx, size_t array_size ) { - wchar_t *end; - + wchar_t *end; + const long size = (long)array_size; - size_t pos = 1; //skip past the opening square bracket - - // debug( 0, L"parse_slice on '%ls'", in ); - - while( 1 ) - { - long tmp; - - while( iswspace(in[pos]) || (in[pos]==INTERNAL_SEPARATOR)) - pos++; - - if( in[pos] == L']' ) - { - pos++; - break; - } - - errno=0; - tmp = wcstol( &in[pos], &end, 10 ); - if( ( errno ) || ( end == &in[pos] ) ) - { - return 1; - } - // debug( 0, L"Push idx %d", tmp ); - - long i1 = tmp>-1 ? tmp : (long)array_size+tmp+1; - pos = end-in; - while( in[pos]==INTERNAL_SEPARATOR ) - pos++; - if ( in[pos]==L'.' && in[pos+1]==L'.' ){ - pos+=2; - while( in[pos]==INTERNAL_SEPARATOR ) - pos++; - long tmp1 = wcstol( &in[pos], &end, 10 ); - if( ( errno ) || ( end == &in[pos] ) ) - { - return 1; - } - pos = end-in; - - // debug( 0, L"Push range %d %d", tmp, tmp1 ); - long i2 = tmp1>-1 ? tmp1 : size+tmp1+1; - // debug( 0, L"Push range idx %d %d", i1, i2 ); - short direction = i2<i1 ? -1 : 1 ; - for (long jjj = i1; jjj*direction <= i2*direction; jjj+=direction) { - // debug(0, L"Expand range [subst]: %i\n", jjj); - idx.push_back( jjj ); - } - continue; - } - - // debug( 0, L"Push idx %d", tmp ); - idx.push_back( i1 ); - } - - if( end_ptr ) - { - // debug( 0, L"Remainder is '%ls', slice def was %d characters long", in+pos, pos ); - - *end_ptr = (wchar_t *)(in+pos); - } - // debug( 0, L"ok, done" ); - - return 0; + size_t pos = 1; //skip past the opening square bracket + + // debug( 0, L"parse_slice on '%ls'", in ); + + while( 1 ) + { + long tmp; + + while( iswspace(in[pos]) || (in[pos]==INTERNAL_SEPARATOR)) + pos++; + + if( in[pos] == L']' ) + { + pos++; + break; + } + + errno=0; + tmp = wcstol( &in[pos], &end, 10 ); + if( ( errno ) || ( end == &in[pos] ) ) + { + return 1; + } + // debug( 0, L"Push idx %d", tmp ); + + long i1 = tmp>-1 ? tmp : (long)array_size+tmp+1; + pos = end-in; + while( in[pos]==INTERNAL_SEPARATOR ) + pos++; + if ( in[pos]==L'.' && in[pos+1]==L'.' ){ + pos+=2; + while( in[pos]==INTERNAL_SEPARATOR ) + pos++; + long tmp1 = wcstol( &in[pos], &end, 10 ); + if( ( errno ) || ( end == &in[pos] ) ) + { + return 1; + } + pos = end-in; + + // debug( 0, L"Push range %d %d", tmp, tmp1 ); + long i2 = tmp1>-1 ? tmp1 : size+tmp1+1; + // debug( 0, L"Push range idx %d %d", i1, i2 ); + short direction = i2<i1 ? -1 : 1 ; + for (long jjj = i1; jjj*direction <= i2*direction; jjj+=direction) { + // debug(0, L"Expand range [subst]: %i\n", jjj); + idx.push_back( jjj ); + } + continue; + } + + // debug( 0, L"Push idx %d", tmp ); + idx.push_back( i1 ); + } + + if( end_ptr ) + { + // debug( 0, L"Remainder is '%ls', slice def was %d characters long", in+pos, pos ); + + *end_ptr = (wchar_t *)(in+pos); + } + // debug( 0, L"ok, done" ); + + return 0; } @@ -975,206 +975,206 @@ static int expand_variables2( parser_t &parser, const wcstring &instr, std::vect static int expand_variables_internal( parser_t &parser, wchar_t * const in, std::vector<completion_t> &out, long last_idx ) { - int is_ok= 1; - int empty=0; - + int is_ok= 1; + int empty=0; + wcstring var_tmp; std::vector<long> var_idx_list; - - // CHECK( out, 0 ); - - for( long i=last_idx; (i>=0) && is_ok && !empty; i-- ) - { - const wchar_t c = in[i]; - if( ( c == VARIABLE_EXPAND ) || (c == VARIABLE_EXPAND_SINGLE ) ) - { - long start_pos = i+1; - long stop_pos; - long var_len; - int is_single = (c==VARIABLE_EXPAND_SINGLE); - - stop_pos = start_pos; - - while( 1 ) - { - if( !(in[stop_pos ]) ) - break; - if( !( iswalnum( in[stop_pos] ) || + + // CHECK( out, 0 ); + + for( long i=last_idx; (i>=0) && is_ok && !empty; i-- ) + { + const wchar_t c = in[i]; + if( ( c == VARIABLE_EXPAND ) || (c == VARIABLE_EXPAND_SINGLE ) ) + { + long start_pos = i+1; + long stop_pos; + long var_len; + int is_single = (c==VARIABLE_EXPAND_SINGLE); + + stop_pos = start_pos; + + while( 1 ) + { + if( !(in[stop_pos ]) ) + break; + if( !( iswalnum( in[stop_pos] ) || (wcschr(L"_", in[stop_pos])!= 0) ) ) - break; - - stop_pos++; - } - - /* printf( "Stop for '%c'\n", in[stop_pos]);*/ - - var_len = stop_pos - start_pos; - - if( var_len == 0 ) - { - expand_variable_error( parser, in, stop_pos-1, -1 ); - - is_ok = 0; - break; - } - + break; + + stop_pos++; + } + + /* printf( "Stop for '%c'\n", in[stop_pos]);*/ + + var_len = stop_pos - start_pos; + + if( var_len == 0 ) + { + expand_variable_error( parser, in, stop_pos-1, -1 ); + + is_ok = 0; + break; + } + var_tmp.append(in + start_pos, var_len); - env_var_t var_val = expand_var(var_tmp.c_str() ); - - if( ! var_val.missing() ) - { - int all_vars=1; + env_var_t var_val = expand_var(var_tmp.c_str() ); + + if( ! var_val.missing() ) + { + int all_vars=1; wcstring_list_t var_item_list; - - if( is_ok ) - { - tokenize_variable_array( var_val.c_str(), var_item_list ); - - if( in[stop_pos] == L'[' ) - { - wchar_t *slice_end; - all_vars=0; - - if( parse_slice( in + stop_pos, &slice_end, var_idx_list, var_item_list.size() ) ) - { - parser.error( SYNTAX_ERROR, + + if( is_ok ) + { + tokenize_variable_array( var_val.c_str(), var_item_list ); + + if( in[stop_pos] == L'[' ) + { + wchar_t *slice_end; + all_vars=0; + + if( parse_slice( in + stop_pos, &slice_end, var_idx_list, var_item_list.size() ) ) + { + parser.error( SYNTAX_ERROR, -1, - L"Invalid index value" ); - is_ok = 0; - break; - } - stop_pos = (slice_end-in); - } - - if( !all_vars ) - { + L"Invalid index value" ); + is_ok = 0; + break; + } + stop_pos = (slice_end-in); + } + + if( !all_vars ) + { wcstring_list_t string_values(var_idx_list.size()); - - for( size_t j=0; j<var_idx_list.size(); j++) - { - long tmp = var_idx_list.at(j); - /* + + for( size_t j=0; j<var_idx_list.size(); j++) + { + long tmp = var_idx_list.at(j); + /* Check that we are within array bounds. If not, truncate the list to exit. */ - if( tmp < 1 || (size_t)tmp > var_item_list.size() ) - { - parser.error( SYNTAX_ERROR, + if( tmp < 1 || (size_t)tmp > var_item_list.size() ) + { + parser.error( SYNTAX_ERROR, -1, ARRAY_BOUNDS_ERR ); - is_ok=0; - var_idx_list.resize(j); - break; - } - else - { - /* Replace each index in var_idx_list inplace with the string value at the specified index */ - //al_set( var_idx_list, j, wcsdup((const wchar_t *)al_get( &var_item_list, tmp-1 ) ) ); + is_ok=0; + var_idx_list.resize(j); + break; + } + else + { + /* Replace each index in var_idx_list inplace with the string value at the specified index */ + //al_set( var_idx_list, j, wcsdup((const wchar_t *)al_get( &var_item_list, tmp-1 ) ) ); string_values.at(j) = var_item_list.at(tmp-1); - } - } - + } + } + // string_values is the new var_item_list var_item_list.swap(string_values); - } - } - - if( is_ok ) - { - - if( is_single ) - { + } + } + + if( is_ok ) + { + + if( is_single ) + { in[i]=0; wcstring res = in; res.push_back(INTERNAL_SEPARATOR); - - for( size_t j=0; j<var_item_list.size(); j++ ) - { - const wcstring &next = var_item_list.at(j); - if( is_ok ) - { - if( j != 0 ) - res.append(L" "); - res.append(next); - } - } + + for( size_t j=0; j<var_item_list.size(); j++ ) + { + const wcstring &next = var_item_list.at(j); + if( is_ok ) + { + if( j != 0 ) + res.append(L" "); + res.append(next); + } + } res.append(in + stop_pos); - is_ok &= expand_variables2( parser, res, out, i ); - } - else - { - for( size_t j=0; j<var_item_list.size(); j++ ) - { - const wcstring &next = var_item_list.at(j); - if( is_ok && (i == 0) && (!in[stop_pos]) ) - { + is_ok &= expand_variables2( parser, res, out, i ); + } + else + { + for( size_t j=0; j<var_item_list.size(); j++ ) + { + const wcstring &next = var_item_list.at(j); + if( is_ok && (i == 0) && (!in[stop_pos]) ) + { append_completion(out, next); - } - else - { - - if( is_ok ) - { + } + else + { + + if( is_ok ) + { wcstring new_in; - + if (start_pos > 0) new_in.append(in, start_pos - 1); - + // at this point new_in.size() is start_pos - 1 if(start_pos>1 && new_in[start_pos-2]!=VARIABLE_EXPAND) { new_in.push_back(INTERNAL_SEPARATOR); - } + } new_in.append(next); - new_in.append(in + stop_pos); + new_in.append(in + stop_pos); is_ok &= expand_variables2( parser, new_in, out, i ); - } - } - - } - } - } - - return is_ok; - } - else - { - /* + } + } + + } + } + } + + return is_ok; + } + else + { + /* Expand a non-existing variable */ - if( c == VARIABLE_EXPAND ) - { - /* + if( c == VARIABLE_EXPAND ) + { + /* Regular expansion, i.e. expand this argument to nothing */ - empty = 1; - } - else - { - /* + empty = 1; + } + else + { + /* Expansion to single argument. */ - wcstring res; + wcstring res; in[i] = 0; res.append(in); res.append(in + stop_pos); - - is_ok &= expand_variables2( parser, res, out, i ); - return is_ok; - } - } - - - } - } - - if( !empty ) - { + + is_ok &= expand_variables2( parser, res, out, i ); + return is_ok; + } + } + + + } + } + + if( !empty ) + { append_completion(out, in); - } - - return is_ok; + } + + return is_ok; } /** @@ -1182,130 +1182,130 @@ static int expand_variables_internal( parser_t &parser, wchar_t * const in, std: */ static int expand_brackets(parser_t &parser, const wcstring &instr, int flags, std::vector<completion_t> &out ) { - const wchar_t *pos; - bool syntax_error = false; - int bracket_count=0; + const wchar_t *pos; + bool syntax_error = false; + int bracket_count=0; + + const wchar_t *bracket_begin=0, *bracket_end=0; + const wchar_t *last_sep=0; - const wchar_t *bracket_begin=0, *bracket_end=0; - const wchar_t *last_sep=0; + const wchar_t *item_begin; + size_t len1, len2, tot_len; - const wchar_t *item_begin; - size_t len1, len2, tot_len; - const wchar_t * const in = instr.c_str(); - - for( pos=in; - (*pos) && !syntax_error; - pos++ ) - { - switch( *pos ) - { - case BRACKET_BEGIN: - { - bracket_begin = pos; - - bracket_count++; - break; - - } - case BRACKET_END: - { - bracket_count--; - if( bracket_end < bracket_begin ) - { - bracket_end = pos; - } - - if( bracket_count < 0 ) - { - syntax_error = true; - } - break; - } - case BRACKET_SEP: - { - if( bracket_count == 1 ) - last_sep = pos; - } - } - } - - if( bracket_count > 0 ) - { - if( !(flags & ACCEPT_INCOMPLETE) ) - { - syntax_error = true; - } - else - { + + for( pos=in; + (*pos) && !syntax_error; + pos++ ) + { + switch( *pos ) + { + case BRACKET_BEGIN: + { + bracket_begin = pos; + + bracket_count++; + break; + + } + case BRACKET_END: + { + bracket_count--; + if( bracket_end < bracket_begin ) + { + bracket_end = pos; + } + + if( bracket_count < 0 ) + { + syntax_error = true; + } + break; + } + case BRACKET_SEP: + { + if( bracket_count == 1 ) + last_sep = pos; + } + } + } + + if( bracket_count > 0 ) + { + if( !(flags & ACCEPT_INCOMPLETE) ) + { + syntax_error = true; + } + else + { wcstring mod; - if( last_sep ) - { - mod.append( in, bracket_begin-in+1 ); - mod.append( last_sep+1 ); - mod.push_back( BRACKET_END ); - } - else - { + if( last_sep ) + { + mod.append( in, bracket_begin-in+1 ); + mod.append( last_sep+1 ); + mod.push_back( BRACKET_END ); + } + else + { mod.append(in); mod.push_back(BRACKET_END); - } - - return expand_brackets( parser, mod, 1, out ); - } - } - - if( syntax_error ) - { - parser.error( SYNTAX_ERROR, - -1, - _(L"Mismatched brackets") ); - return 0; - } - - if( bracket_begin == 0 ) - { - append_completion(out, in); - return 1; - } - - len1 = (bracket_begin-in); - len2 = wcslen(bracket_end)-1; - tot_len = len1+len2; - item_begin = bracket_begin+1; - for( pos=(bracket_begin+1); 1; pos++ ) - { - if( bracket_count == 0 ) - { - if( (*pos == BRACKET_SEP) || (pos==bracket_end) ) - { + } + + return expand_brackets( parser, mod, 1, out ); + } + } + + if( syntax_error ) + { + parser.error( SYNTAX_ERROR, + -1, + _(L"Mismatched brackets") ); + return 0; + } + + if( bracket_begin == 0 ) + { + append_completion(out, in); + return 1; + } + + len1 = (bracket_begin-in); + len2 = wcslen(bracket_end)-1; + tot_len = len1+len2; + item_begin = bracket_begin+1; + for( pos=(bracket_begin+1); 1; pos++ ) + { + if( bracket_count == 0 ) + { + if( (*pos == BRACKET_SEP) || (pos==bracket_end) ) + { assert(pos >= item_begin); - size_t item_len = pos-item_begin; - + size_t item_len = pos-item_begin; + wcstring whole_item; whole_item.reserve(tot_len + item_len + 2); whole_item.append(in, len1); whole_item.append(item_begin, item_len); whole_item.append(bracket_end + 1); expand_brackets( parser, whole_item, flags, out ); - - item_begin = pos+1; - if( pos == bracket_end ) - break; - } - } - - if( *pos == BRACKET_BEGIN ) - { - bracket_count++; - } - - if( *pos == BRACKET_END ) - { - bracket_count--; - } - } - return 1; + + item_begin = pos+1; + if( pos == bracket_end ) + break; + } + } + + if( *pos == BRACKET_BEGIN ) + { + bracket_count++; + } + + if( *pos == BRACKET_END ) + { + bracket_count--; + } + } + return 1; } /** @@ -1313,85 +1313,85 @@ static int expand_brackets(parser_t &parser, const wcstring &instr, int flags, s */ static int expand_cmdsubst( parser_t &parser, const wcstring &input, std::vector<completion_t> &outList ) { - wchar_t *paran_begin=0, *paran_end=0; + wchar_t *paran_begin=0, *paran_end=0; std::vector<wcstring> sub_res; - size_t i, j; - wchar_t *tail_begin = 0; - + size_t i, j; + wchar_t *tail_begin = 0; + const wchar_t * const in = input.c_str(); - - int parse_ret; - switch( parse_ret = parse_util_locate_cmdsubst(in, + + int parse_ret; + switch( parse_ret = parse_util_locate_cmdsubst(in, ¶n_begin, ¶n_end, 0 ) ) - { - case -1: - parser.error( SYNTAX_ERROR, + { + case -1: + parser.error( SYNTAX_ERROR, -1, L"Mismatched parenthesis" ); - return 0; - case 0: + return 0; + case 0: outList.push_back(completion_t(input)); - return 1; - case 1: - - break; - } - + return 1; + case 1: + + break; + } + const wcstring subcmd(paran_begin + 1, paran_end-paran_begin - 1); - - if( exec_subshell( subcmd, sub_res) == -1 ) - { - parser.error( CMDSUBST_ERROR, -1, L"Unknown error while evaulating command substitution" ); - return 0; - } - - tail_begin = paran_end + 1; - if( *tail_begin == L'[' ) - { + + if( exec_subshell( subcmd, sub_res) == -1 ) + { + parser.error( CMDSUBST_ERROR, -1, L"Unknown error while evaulating command substitution" ); + return 0; + } + + tail_begin = paran_end + 1; + if( *tail_begin == L'[' ) + { std::vector<long> slice_idx; - wchar_t *slice_end; - - if( parse_slice( tail_begin, &slice_end, slice_idx, sub_res.size() ) ) - { - parser.error( SYNTAX_ERROR, -1, L"Invalid index value" ); - return 0; - } - else - { + wchar_t *slice_end; + + if( parse_slice( tail_begin, &slice_end, slice_idx, sub_res.size() ) ) + { + parser.error( SYNTAX_ERROR, -1, L"Invalid index value" ); + return 0; + } + else + { std::vector<wcstring> sub_res2; - tail_begin = slice_end; - for( i=0; i < slice_idx.size(); i++ ) - { - long idx = slice_idx.at(i); - if( idx < 1 || (size_t)idx > sub_res.size() ) - { - parser.error( SYNTAX_ERROR, - -1, - ARRAY_BOUNDS_ERR ); - return 0; - } - idx = idx-1; - + tail_begin = slice_end; + for( i=0; i < slice_idx.size(); i++ ) + { + long idx = slice_idx.at(i); + if( idx < 1 || (size_t)idx > sub_res.size() ) + { + parser.error( SYNTAX_ERROR, + -1, + ARRAY_BOUNDS_ERR ); + return 0; + } + idx = idx-1; + sub_res2.push_back(sub_res.at(idx)); - // debug( 0, L"Pushing item '%ls' with index %d onto sliced result", al_get( sub_res, idx ), idx ); - //sub_res[idx] = 0; // ?? - } - sub_res = sub_res2; - } - } - - - /* + // debug( 0, L"Pushing item '%ls' with index %d onto sliced result", al_get( sub_res, idx ), idx ); + //sub_res[idx] = 0; // ?? + } + sub_res = sub_res2; + } + } + + + /* Recursively call ourselves to expand any remaining command substitutions. The result of this recursive call using the tail of the string is inserted into the tail_expand array list */ std::vector<completion_t> tail_expand; - expand_cmdsubst( parser, tail_begin, tail_expand ); - - /* + expand_cmdsubst( parser, tail_begin, tail_expand ); + + /* Combine the result of the current command substitution with the result of the recursive tail expansion */ @@ -1399,35 +1399,35 @@ static int expand_cmdsubst( parser_t &parser, const wcstring &input, std::vector { wcstring sub_item = sub_res.at(i); wcstring sub_item2 = escape_string(sub_item, 1); - + for( j=0; j < tail_expand.size(); j++ ) { - + wcstring whole_item; - + wcstring tail_item = tail_expand.at(j).completion; - + //sb_append_substring( &whole_item, in, len1 ); whole_item.append(in, paran_begin-in); - + //sb_append_char( &whole_item, INTERNAL_SEPARATOR ); whole_item.push_back(INTERNAL_SEPARATOR); - + //sb_append_substring( &whole_item, sub_item2, item_len ); - whole_item.append(sub_item2); - + whole_item.append(sub_item2); + //sb_append_char( &whole_item, INTERNAL_SEPARATOR ); whole_item.push_back(INTERNAL_SEPARATOR); - + //sb_append( &whole_item, tail_item ); whole_item.append(tail_item); - - //al_push( out, whole_item.buff ); + + //al_push( out, whole_item.buff ); outList.push_back(completion_t(whole_item)); } } - - return 1; + + return 1; } /** @@ -1436,10 +1436,10 @@ static int expand_cmdsubst( parser_t &parser, const wcstring &input, std::vector __attribute__((unused)) static wchar_t *expand_unescape( parser_t &parser, const wchar_t * in, int escape_special ) { - wchar_t *res = unescape( in, escape_special ); - if( !res ) - parser.error( SYNTAX_ERROR, -1, L"Unexpected end of string" ); - return res; + wchar_t *res = unescape( in, escape_special ); + if( !res ) + parser.error( SYNTAX_ERROR, -1, L"Unexpected end of string" ); + return res; } static wcstring expand_unescape_string( const wcstring &in, int escape_special ) @@ -1447,7 +1447,7 @@ static wcstring expand_unescape_string( const wcstring &in, int escape_special ) wcstring tmp = in; unescape_string(tmp, escape_special); /* Need to detect error here */ - return tmp; + return tmp; } /** @@ -1455,24 +1455,24 @@ static wcstring expand_unescape_string( const wcstring &in, int escape_special ) */ static void expand_home_directory( wcstring &input ) { - const wchar_t * const in = input.c_str(); - if( in[0] == HOME_DIRECTORY ) - { - int tilde_error = 0; + const wchar_t * const in = input.c_str(); + if( in[0] == HOME_DIRECTORY ) + { + int tilde_error = 0; size_t tail_idx; wcstring home; - if( in[1] == '/' || in[1] == '\0' ) - { - /* Current users home directory */ + if( in[1] == '/' || in[1] == '\0' ) + { + /* Current users home directory */ - home = env_get_string( L"HOME" ); + home = env_get_string( L"HOME" ); tail_idx = 1; - } - else - { - /* Some other users home directory */ - const wchar_t *name_end = wcschr( in, L'/' ); + } + else + { + /* Some other users home directory */ + const wchar_t *name_end = wcschr( in, L'/' ); if (name_end) { tail_idx = name_end - in; @@ -1483,33 +1483,33 @@ static void expand_home_directory( wcstring &input ) } wcstring name_str = input.substr(1, tail_idx - 1); std::string name_cstr = wcs2string(name_str); - struct passwd *userinfo = getpwnam( name_cstr.c_str() ); + struct passwd *userinfo = getpwnam( name_cstr.c_str() ); - if( userinfo == NULL ) - { - tilde_error = 1; + if( userinfo == NULL ) + { + tilde_error = 1; input[0] = L'~'; - } - else - { - home = str2wcstring(userinfo->pw_dir); - } - } + } + else + { + home = str2wcstring(userinfo->pw_dir); + } + } if (! tilde_error) { input.replace(input.begin(), input.begin() + tail_idx, home); } - } + } } void expand_tilde(wcstring &input) { - if( ! input.empty() && input.at(0) == L'~' ) - { - input.at(0) = HOME_DIRECTORY; - expand_home_directory( input ); - } + if( ! input.empty() && input.at(0) == L'~' ) + { + input.at(0) = HOME_DIRECTORY; + expand_home_directory( input ); + } } /** @@ -1520,7 +1520,7 @@ static void remove_internal_separator( wcstring &str, bool conv ) { /* Remove all instances of INTERNAL_SEPARATOR */ str.erase(std::remove(str.begin(), str.end(), (wchar_t)INTERNAL_SEPARATOR), str.end()); - + /* If conv is true, replace all instances of ANY_CHAR with '?', ANY_STRING with '*', ANY_STRING_RECURSIVE with '*' */ if (conv) { @@ -1543,43 +1543,43 @@ static void remove_internal_separator( wcstring &str, bool conv ) int expand_string( const wcstring &input, std::vector<completion_t> &output, expand_flags_t flags ) { - parser_t parser(PARSER_TYPE_ERRORS_ONLY, true /* show errors */); - std::vector<completion_t> list1, list2; - std::vector<completion_t> *in, *out; - - size_t i; - int res = EXPAND_OK; - - if( (!(flags & ACCEPT_INCOMPLETE)) && expand_is_clean( input.c_str() ) ) - { - output.push_back(completion_t(input)); - return EXPAND_OK; - } - - if( EXPAND_SKIP_CMDSUBST & flags ) - { - wchar_t *begin, *end; - - if( parse_util_locate_cmdsubst( input.c_str(), + parser_t parser(PARSER_TYPE_ERRORS_ONLY, true /* show errors */); + std::vector<completion_t> list1, list2; + std::vector<completion_t> *in, *out; + + size_t i; + int res = EXPAND_OK; + + if( (!(flags & ACCEPT_INCOMPLETE)) && expand_is_clean( input.c_str() ) ) + { + output.push_back(completion_t(input)); + return EXPAND_OK; + } + + if( EXPAND_SKIP_CMDSUBST & flags ) + { + wchar_t *begin, *end; + + if( parse_util_locate_cmdsubst( input.c_str(), &begin, &end, 1 ) != 0 ) - { - parser.error( CMDSUBST_ERROR, -1, L"Command substitutions not allowed" ); - return EXPAND_ERROR; - } - list1.push_back(completion_t(input)); - } - else - { + { + parser.error( CMDSUBST_ERROR, -1, L"Command substitutions not allowed" ); + return EXPAND_ERROR; + } + list1.push_back(completion_t(input)); + } + else + { int cmdsubst_ok = expand_cmdsubst(parser, input, list1); if (! cmdsubst_ok) return EXPAND_ERROR; - } + } in = &list1; out = &list2; - + for( i=0; i < in->size(); i++ ) { /* @@ -1587,9 +1587,9 @@ int expand_string( const wcstring &input, std::vector<completion_t> &output, exp expand_string to expand incomplete strings from the commandline. */ - int unescape_flags = UNESCAPE_SPECIAL | UNESCAPE_INCOMPLETE; + int unescape_flags = UNESCAPE_SPECIAL | UNESCAPE_INCOMPLETE; wcstring next = expand_unescape_string( in->at(i).completion, unescape_flags ); - + if( EXPAND_SKIP_VARIABLES & flags ) { for (size_t i=0; i < next.size(); i++) { @@ -1607,33 +1607,33 @@ int expand_string( const wcstring &input, std::vector<completion_t> &output, exp } } } - + in->clear(); - + in = &list2; out = &list1; - + for( i=0; i < in->size(); i++ ) { wcstring next = in->at(i).completion; - + if( !expand_brackets( parser, next, flags, *out )) { return EXPAND_ERROR; } } in->clear(); - + in = &list1; out = &list2; - + for( i=0; i < in->size(); i++ ) { wcstring next = in->at(i).completion; - + expand_home_directory(next); - - + + if( flags & ACCEPT_INCOMPLETE ) { if( next[0] == PROCESS_EXPAND ) @@ -1660,26 +1660,26 @@ int expand_string( const wcstring &input, std::vector<completion_t> &output, exp } } } - + in->clear(); - + in = &list2; out = &list1; - + for( i=0; i < in->size(); i++ ) { wcstring next_str = in->at(i).completion; int wc_res; - - remove_internal_separator( next_str, (EXPAND_SKIP_WILDCARDS & flags) ? true : false ); + + remove_internal_separator( next_str, (EXPAND_SKIP_WILDCARDS & flags) ? true : false ); const wchar_t *next = next_str.c_str(); - + if( ((flags & ACCEPT_INCOMPLETE) && (!(flags & EXPAND_SKIP_WILDCARDS))) || wildcard_has( next, 1 ) ) { const wchar_t *start, *rest; std::vector<completion_t> *list = out; - + if( next[0] == '/' ) { start = L"/"; @@ -1690,17 +1690,17 @@ int expand_string( const wcstring &input, std::vector<completion_t> &output, exp start = L""; rest = next; } - + if( flags & ACCEPT_INCOMPLETE ) { list = &output; } - + wc_res = wildcard_expand_string(rest, start, flags, *list); - + if( !(flags & ACCEPT_INCOMPLETE) ) { - + switch( wc_res ) { case 0: @@ -1712,13 +1712,13 @@ int expand_string( const wcstring &input, std::vector<completion_t> &output, exp break; } } - + case 1: { size_t j; res = EXPAND_WILDCARD_MATCH; sort_completions( *out ); - + for( j=0; j< out->size(); j++ ) { output.push_back( out->at(j) ); @@ -1726,15 +1726,15 @@ int expand_string( const wcstring &input, std::vector<completion_t> &output, exp out->clear(); break; } - + case -1: { return EXPAND_ERROR; } - + } } - + } else { @@ -1746,26 +1746,26 @@ int expand_string( const wcstring &input, std::vector<completion_t> &output, exp output.push_back(completion_t(next)); } } - + } - - return res; + + return res; } bool expand_one(wcstring &string, expand_flags_t flags) { - std::vector<completion_t> completions; - bool result = false; - - if( (!(flags & ACCEPT_INCOMPLETE)) && expand_is_clean( string.c_str() ) ) - { + std::vector<completion_t> completions; + bool result = false; + + if( (!(flags & ACCEPT_INCOMPLETE)) && expand_is_clean( string.c_str() ) ) + { return true; - } - + } + if (expand_string(string, completions, flags)) { if (completions.size() == 1) { string = completions.at(0).completion; result = true; } } - return result; + return result; } |