Esempio n. 1
0
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;

    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]) ||
                        (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;
            }

            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;
                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,
                                         -1,
                                         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);
                            /*
                                           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,
                                             -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 ) ) );
                                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)
                    {
                        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);
                            }
                        }
                        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]))
                            {
                                append_completion(out, next);
                            }
                            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);
                                    is_ok &= expand_variables2(parser, new_in, out, i);
                                }
                            }

                        }
                    }
                }

                return is_ok;
            }
            else
            {
                /*
                         Expand a non-existing variable
                         */
                if (c == VARIABLE_EXPAND)
                {
                    /*
                               Regular expansion, i.e. expand this argument to nothing
                               */
                    empty = 1;
                }
                else
                {
                    /*
                               Expansion to single argument.
                               */
                    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)
    {
        append_completion(out, in);
    }

    return is_ok;
}
Esempio n. 2
0
/**
 Perform cmdsubst expansion
 */
static int expand_cmdsubst(parser_t &parser, const wcstring &input, std::vector<completion_t> &outList)
{
    wchar_t *paran_begin=0, *paran_end=0;
    std::vector<wcstring> sub_res;
    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,
                        &paran_begin,
                        &paran_end,
                        0))
    {
        case -1:
            parser.error(SYNTAX_ERROR,
                         -1,
                         L"Mismatched parenthesis");
            return 0;
        case 0:
            outList.push_back(completion_t(input));
            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'[')
    {
        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
        {
            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;

                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;
        }
    }


    /*
       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);

    /*
       Combine the result of the current command substitution with the
       result of the recursive tail expansion
       */
    for (i=0; i<sub_res.size(); i++)
    {
        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);

            //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 );
            outList.push_back(completion_t(whole_item));
        }
    }

    return 1;
}
Esempio n. 3
0
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:
        {
            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;
        }
    }
}
Esempio n. 4
0
/**
   Perform bracket expansion
*/
static int expand_brackets(parser_t &parser, const wcstring &instr, int flags, std::vector<completion_t> &out)
{
    bool syntax_error = false;
    int bracket_count=0;

    const wchar_t *bracket_begin = NULL, *bracket_end = NULL;
    const wchar_t *last_sep = NULL;

    const wchar_t *item_begin;
    size_t length_preceding_brackets, length_following_brackets, tot_len;

    const wchar_t * const in = instr.c_str();

    /* Locate the first non-nested bracket pair */
    for (const wchar_t *pos = in; (*pos) && !syntax_error; pos++)
    {
        switch (*pos)
        {
            case BRACKET_BEGIN:
            {
                if (bracket_count == 0)
                    bracket_begin = pos;
                bracket_count++;
                break;

            }
            case BRACKET_END:
            {
                bracket_count--;
                if (bracket_count < 0)
                {
                    syntax_error = true;
                }
                else if (bracket_count == 0)
                {
                    bracket_end = pos;
                    break;
                }

            }
            case BRACKET_SEP:
            {
                if (bracket_count == 1)
                    last_sep = pos;
            }
        }
    }

    if (bracket_count > 0)
    {
        if (!(flags & ACCEPT_INCOMPLETE))
        {
            syntax_error = true;
        }
        else
        {
            /* The user hasn't typed an end bracket yet; make one up and append it, then expand that. */
            wcstring mod;
            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 == NULL)
    {
        append_completion(out, instr);
        return 1;
    }

    length_preceding_brackets = (bracket_begin-in);
    length_following_brackets = wcslen(bracket_end)-1;
    tot_len = length_preceding_brackets+length_following_brackets;
    item_begin = bracket_begin+1;
    for (const wchar_t *pos =(bracket_begin+1); true; pos++)
    {
        if (bracket_count == 0)
        {
            if ((*pos == BRACKET_SEP) || (pos==bracket_end))
            {
                assert(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, length_preceding_brackets);
                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;
}