Exemplo n.º 1
0
jv jv_get(jv t, jv k) {
  jv v;
  if (jv_get_kind(t) == JV_KIND_OBJECT && jv_get_kind(k) == JV_KIND_STRING) {
    v = jv_object_get(t, k);
    if (!jv_is_valid(v)) {
      jv_free(v);
      v = jv_null();
    }
  } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_NUMBER) {
    if(jv_is_integer(k)){
      v = jv_array_get(t, (int)jv_number_value(k));
      if (!jv_is_valid(v)) {
        jv_free(v);
        v = jv_null();
      }
    } else {
      jv_free(t);
      jv_free(k);
      v = jv_null();
    }
  } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_OBJECT) {
    int start, end;
    if (parse_slice(t, k, &start, &end)) {
      v = jv_array_slice(t, start, end);
    } else {
      v = jv_invalid_with_msg(jv_string_fmt("Start and end indices of an array slice must be numbers"));
      jv_free(t);
    }
  } else if (jv_get_kind(t) == JV_KIND_STRING && jv_get_kind(k) == JV_KIND_OBJECT) {
    int start, end;
    if (parse_slice(t, k, &start, &end)) {
      v = jv_string_slice(t, start, end);
    } else {
      v = jv_invalid_with_msg(jv_string_fmt("Start and end indices of an string slice must be numbers"));
      jv_free(t);
    }
  } else if (jv_get_kind(t) == JV_KIND_STRING && jv_get_kind(k) == JV_KIND_STRING) {
    v = jv_string_indexes(t, k);
  } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_ARRAY) {
    v = jv_array_indexes(t, k);
  } else if (jv_get_kind(t) == JV_KIND_NULL && 
             (jv_get_kind(k) == JV_KIND_STRING || 
              jv_get_kind(k) == JV_KIND_NUMBER || 
              jv_get_kind(k) == JV_KIND_OBJECT)) {
    jv_free(t);
    jv_free(k);
    v = jv_null();
  } else {
    v = jv_invalid_with_msg(jv_string_fmt("Cannot index %s with %s",
                                          jv_kind_name(jv_get_kind(t)),
                                          jv_kind_name(jv_get_kind(k))));
    jv_free(t);
    jv_free(k);
  }
  return v;
}
Exemplo n.º 2
0
Arquivo: jv_aux.c Projeto: 4honor/jq
// assumes keys is a sorted array
jv jv_dels(jv t, jv keys) {
  assert(jv_get_kind(keys) == JV_KIND_ARRAY);
  assert(jv_is_valid(t));
  
  if (jv_get_kind(t) == JV_KIND_NULL || jv_array_length(jv_copy(keys)) == 0) {
    // no change
  } else if (jv_get_kind(t) == JV_KIND_ARRAY) {
    // extract slices, they must be handled differently
    jv orig_keys = keys;
    keys = jv_array();
    jv new_array = jv_array();
    jv starts = jv_array(), ends = jv_array();
    jv_array_foreach(orig_keys, i, key) {
      if (jv_get_kind(key) == JV_KIND_NUMBER) {
        keys = jv_array_append(keys, key);
      } else if (jv_get_kind(key) == JV_KIND_OBJECT) {
        int start, end;
        if (parse_slice(t, key, &start, &end)) {
          starts = jv_array_append(starts, jv_number(start));
          ends = jv_array_append(ends, jv_number(end));
        } else {
          jv_free(new_array);
          jv_free(key);
          new_array = jv_invalid_with_msg(jv_string_fmt("Start and end indices of an array slice must be numbers"));
          goto arr_out;
        }
      } else {
        jv_free(new_array);
        new_array = jv_invalid_with_msg(jv_string_fmt("Cannot delete %s element of array",
                                                      jv_kind_name(jv_get_kind(key))));
        jv_free(key);
        goto arr_out;
      }
    }

    int kidx = 0;
    jv_array_foreach(t, i, elem) {
      int del = 0;
      while (kidx < jv_array_length(jv_copy(keys))) {
        int delidx = (int)jv_number_value(jv_array_get(jv_copy(keys), kidx));
        if (i == delidx) {
          del = 1;
        }
        if (i < delidx) {
          break;
        }
        kidx++;
      }
      for (int sidx=0; !del && sidx<jv_array_length(jv_copy(starts)); sidx++) {
        if ((int)jv_number_value(jv_array_get(jv_copy(starts), sidx)) <= i &&
            i < (int)jv_number_value(jv_array_get(jv_copy(ends), sidx))) {
          del = 1;
        }
      }
      if (!del)
        new_array = jv_array_append(new_array, elem);
      else
        jv_free(elem);
    }
Exemplo n.º 3
0
int
semver_parse (const char *str, semver_t *ver) {
  int valid, res;
  size_t len;
  char *buf;
  valid = semver_is_valid(str);
  if (!valid) return -1;

  len = strlen(str);
  buf = calloc(len + 1, sizeof(*buf));
  if (buf == NULL) return -1;
  strcpy(buf, str);

  ver->metadata = parse_slice(buf, MT_DELIMITER[0]);
  ver->prerelease = parse_slice(buf, PR_DELIMITER[0]);

  res = semver_parse_version(buf, ver);
  free(buf);
#if DEBUG > 0
  printf("[debug] semver.c %s = %d.%d.%d, %s %s\n", str, ver->major, ver->minor, ver->patch, ver->prerelease, ver->metadata);
#endif
  return res;
}
Exemplo n.º 4
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;
}
Exemplo n.º 5
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;
}
Exemplo n.º 6
0
Arquivo: jv_aux.c Projeto: 4honor/jq
jv jv_get(jv t, jv k) {
  jv v;
  if (jv_get_kind(t) == JV_KIND_OBJECT && jv_get_kind(k) == JV_KIND_STRING) {
    v = jv_object_get(t, k);
    if (!jv_is_valid(v)) {
      jv_free(v);
      v = jv_null();
    }
  } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_NUMBER) {
    if(jv_is_integer(k)){
      int idx = (int)jv_number_value(k);
      if (idx < 0)
        idx += jv_array_length(jv_copy(t));
      v = jv_array_get(t, idx);
      if (!jv_is_valid(v)) {
        jv_free(v);
        v = jv_null();
      }
    } else {
      jv_free(t);
      jv_free(k);
      v = jv_null();
    }
  } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_OBJECT) {
    int start, end;
    if (parse_slice(t, k, &start, &end)) {
      v = jv_array_slice(t, start, end);
    } else {
      v = jv_invalid_with_msg(jv_string_fmt("Start and end indices of an array slice must be numbers"));
      jv_free(t);
    }
  } else if (jv_get_kind(t) == JV_KIND_STRING && jv_get_kind(k) == JV_KIND_OBJECT) {
    int start, end;
    if (parse_slice(t, k, &start, &end)) {
      v = jv_string_slice(t, start, end);
    } else {
      v = jv_invalid_with_msg(jv_string_fmt("Start and end indices of an string slice must be numbers"));
      jv_free(t);
    }
  } else if (jv_get_kind(t) == JV_KIND_STRING && jv_get_kind(k) == JV_KIND_STRING) {
    v = jv_string_indexes(t, k);
  } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_ARRAY) {
    v = jv_array_indexes(t, k);
  } else if (jv_get_kind(t) == JV_KIND_NULL && 
             (jv_get_kind(k) == JV_KIND_STRING || 
              jv_get_kind(k) == JV_KIND_NUMBER || 
              jv_get_kind(k) == JV_KIND_OBJECT)) {
    jv_free(t);
    jv_free(k);
    v = jv_null();
  } else {
    /*
     * If k is a short string it's probably from a jq .foo expression or
     * similar, in which case putting it in the invalid msg may help the
     * user.  The length 30 is arbitrary.
     */
    if (jv_get_kind(k) == JV_KIND_STRING && jv_string_length_bytes(jv_copy(k)) < 30) {
      v = jv_invalid_with_msg(jv_string_fmt("Cannot index %s with string \"%s\"",
                                            jv_kind_name(jv_get_kind(t)),
                                            jv_string_value(k)));
    } else {
      v = jv_invalid_with_msg(jv_string_fmt("Cannot index %s with %s",
                                            jv_kind_name(jv_get_kind(t)),
                                            jv_kind_name(jv_get_kind(k))));
    }
    jv_free(t);
    jv_free(k);
  }
  return v;
}
Exemplo n.º 7
0
Arquivo: jv_aux.c Projeto: 4honor/jq
jv jv_set(jv t, jv k, jv v) {
  if (!jv_is_valid(v)) {
    jv_free(t);
    jv_free(k);
    return v;
  }
  int isnull = jv_get_kind(t) == JV_KIND_NULL;
  if (jv_get_kind(k) == JV_KIND_STRING && 
      (jv_get_kind(t) == JV_KIND_OBJECT || isnull)) {
    if (isnull) t = jv_object();
    t = jv_object_set(t, k, v);
  } else if (jv_get_kind(k) == JV_KIND_NUMBER &&
             (jv_get_kind(t) == JV_KIND_ARRAY || isnull)) {
    if (isnull) t = jv_array();
    t = jv_array_set(t, (int)jv_number_value(k), v);
  } else if (jv_get_kind(k) == JV_KIND_OBJECT &&
             (jv_get_kind(t) == JV_KIND_ARRAY || isnull)) {
    if (isnull) t = jv_array();
    int start, end;
    if (parse_slice(t, k, &start, &end)) {
      if (jv_get_kind(v) == JV_KIND_ARRAY) {
        int array_len = jv_array_length(jv_copy(t));
        assert(0 <= start && start <= end && end <= array_len);
        int slice_len = end - start;
        int insert_len = jv_array_length(jv_copy(v));
        if (slice_len < insert_len) {
          // array is growing
          int shift = insert_len - slice_len;
          for (int i = array_len - 1; i >= end; i--) {
            t = jv_array_set(t, i + shift, jv_array_get(jv_copy(t), i));
          }
        } else if (slice_len > insert_len) {
          // array is shrinking
          int shift = slice_len - insert_len;
          for (int i = end; i < array_len; i++) {
            t = jv_array_set(t, i - shift, jv_array_get(jv_copy(t), i));
          }
          t = jv_array_slice(t, 0, array_len - shift);
        }
        for (int i=0; i < insert_len; i++) {
          t = jv_array_set(t, start + i, jv_array_get(jv_copy(v), i));
        }
        jv_free(v);
      } else {
        jv_free(t);
        jv_free(v);
        t = jv_invalid_with_msg(jv_string_fmt("A slice of an array can only be assigned another array"));
      }
    } else {
      jv_free(t);
      jv_free(k);
      jv_free(v);
      t = jv_invalid_with_msg(jv_string_fmt("Start and end indices of an array slice must be numbers"));
    }
  } else {
    jv err = jv_invalid_with_msg(jv_string_fmt("Cannot update field at %s index of %s",
                                               jv_kind_name(jv_get_kind(k)),
                                               jv_kind_name(jv_get_kind(t))));
    jv_free(t);
    jv_free(k);
    jv_free(v);
    t = err;
  }
  return t;
}
Exemplo n.º 8
0
/// Expand all environment variables in the string *ptr.
///
/// This function is slow, fragile and complicated. There are lots of little corner cases, like
/// $$foo should do a double expansion, $foo$bar should not double expand bar, etc. Also, it's easy
/// to accidentally leak memory on array out of bounds errors an various other situations. All in
/// all, this function should be rewritten, split out into multiple logical units and carefully
/// tested. After that, it can probably be optimized to do fewer memory allocations, fewer string
/// scans and overall just less work. But until that happens, don't edit it unless you know exactly
/// what you are doing, and do proper testing afterwards.
///
/// This function operates on strings backwards, starting at last_idx.
///
/// Note: last_idx is considered to be where it previously finished procesisng. This means it
/// actually starts operating on last_idx-1. As such, to process a string fully, pass string.size()
/// as last_idx instead of string.size()-1.
static bool expand_variables(const wcstring &instr, std::vector<completion_t> *out, size_t last_idx,
                             parse_error_list_t *errors) {
    const size_t insize = instr.size();

    // last_idx may be 1 past the end of the string, but no further.
    assert(last_idx <= insize && "Invalid last_idx");
    if (last_idx == 0) {
        append_completion(out, instr);
        return true;
    }

    // Locate the last VARIABLE_EXPAND or VARIABLE_EXPAND_SINGLE
    bool is_single = false;
    size_t varexp_char_idx = last_idx;
    while (varexp_char_idx--) {
        const wchar_t c = instr.at(varexp_char_idx);
        if (c == VARIABLE_EXPAND || c == VARIABLE_EXPAND_SINGLE) {
            is_single = (c == VARIABLE_EXPAND_SINGLE);
            break;
        }
    }
    if (varexp_char_idx >= instr.size()) {
        // No variable expand char, we're done.
        append_completion(out, instr);
        return true;
    }

    // Get the variable name.
    const size_t var_name_start = varexp_char_idx + 1;
    size_t var_name_stop = var_name_start;
    while (var_name_stop < insize) {
        const wchar_t nc = instr.at(var_name_stop);
        if (nc == VARIABLE_EXPAND_EMPTY) {
            var_name_stop++;
            break;
        }
        if (!valid_var_name_char(nc)) break;
        var_name_stop++;
    }
    assert(var_name_stop >= var_name_start && "Bogus variable name indexes");
    const size_t var_name_len = var_name_stop - var_name_start;

    // It's an error if the name is empty.
    if (var_name_len == 0) {
        if (errors) {
            parse_util_expand_variable_error(instr, 0 /* global_token_pos */, varexp_char_idx,
                                             errors);
        }
        return false;
    }

    // Get the variable name as a string, then try to get the variable from env.
    const wcstring var_name(instr, var_name_start, var_name_len);
    // Do a dirty hack to make sliced history fast (#4650). We expand from either a variable, or a
    // history_t. Note that "history" is read only in env.cpp so it's safe to special-case it in
    // this way (it cannot be shadowed, etc).
    history_t *history = nullptr;
    maybe_t<env_var_t> var{};
    if (var_name == L"history") {
        // We do this only on the main thread, matching env.cpp.
        if (is_main_thread()) {
            history = reader_get_history();
        }
    } else if (var_name != wcstring{VARIABLE_EXPAND_EMPTY}) {
        var = env_get(var_name);
    }

    // Parse out any following slice.
    // Record the end of the variable name and any following slice.
    size_t var_name_and_slice_stop = var_name_stop;
    bool all_values = true;
    const size_t slice_start = var_name_stop;
    // List of indexes, and parallel array of source positions of each index in the variable list.
    std::vector<long> var_idx_list;
    std::vector<size_t> var_pos_list;
    if (slice_start < insize && instr.at(slice_start) == L'[') {
        all_values = false;
        const wchar_t *in = instr.c_str();
        wchar_t *slice_end;
        // If a variable is missing, behave as though we have one value, so that $var[1] always
        // works.
        size_t effective_val_count = 1;
        if (var) {
            effective_val_count = var->as_list().size();
        } else if (history) {
            effective_val_count = history->size();
        }
        size_t bad_pos = parse_slice(in + slice_start, &slice_end, var_idx_list, var_pos_list,
                                     effective_val_count);
        if (bad_pos != 0) {
            append_syntax_error(errors, slice_start + bad_pos, L"Invalid index value");
            return false;
        }
        var_name_and_slice_stop = (slice_end - in);
    }

    if (!var && !history) {
        // Expanding a non-existent variable.
        if (!is_single) {
            // Normal expansions of missing variables successfully expand to nothing.
            return true;
        } else {
            // Expansion to single argument.
            // Replace the variable name and slice with VARIABLE_EXPAND_EMPTY.
            wcstring res(instr, 0, varexp_char_idx);
            if (!res.empty() && res.back() == VARIABLE_EXPAND_SINGLE) {
                res.push_back(VARIABLE_EXPAND_EMPTY);
            }
            res.append(instr, var_name_and_slice_stop, wcstring::npos);
            return expand_variables(res, out, varexp_char_idx, errors);
        }
    }

    // Ok, we have a variable or a history. Let's expand it.
    // Start by respecting the sliced elements.
    assert((var || history) && "Should have variable or history here");
    wcstring_list_t var_item_list;
    if (all_values) {
        if (history) {
            history->get_history(var_item_list);
        } else {
            var->to_list(var_item_list);
        }
    } else {
        // We have to respect the slice.
        if (history) {
            // Ask history to map indexes to item strings.
            // Note this may have missing entries for out-of-bounds.
            auto item_map = history->items_at_indexes(var_idx_list);
            for (long item_index : var_idx_list) {
                auto iter = item_map.find(item_index);
                if (iter != item_map.end()) {
                    var_item_list.push_back(iter->second);
                }
            }
        } else {
            const wcstring_list_t &all_var_items = var->as_list();
            for (long item_index : var_idx_list) {
                // Check that we are within array bounds. If not, skip the element. Note:
                // Negative indices (`echo $foo[-1]`) are already converted to positive ones
                // here, So tmp < 1 means it's definitely not in.
                // Note we are 1-based.
                if (item_index >= 1 && size_t(item_index) <= all_var_items.size()) {
                    var_item_list.push_back(all_var_items.at(item_index - 1));
                }
            }
        }
    }

    if (is_single) {
        wcstring res(instr, 0, varexp_char_idx);
        if (!res.empty()) {
            if (res.back() != VARIABLE_EXPAND_SINGLE) {
                res.push_back(INTERNAL_SEPARATOR);
            } else if (var_item_list.empty() || var_item_list.front().empty()) {
                // First expansion is empty, but we need to recursively expand.
                res.push_back(VARIABLE_EXPAND_EMPTY);
            }
        }

        // Append all entries in var_item_list, separated by spaces.
        // Remove the last space.
        if (!var_item_list.empty()) {
            for (const wcstring &item : var_item_list) {
                res.append(item);
                res.push_back(L' ');
            }
            res.pop_back();
        }
        res.append(instr, var_name_and_slice_stop, wcstring::npos);
        return expand_variables(res, out, varexp_char_idx, errors);
    } else {
        // Normal cartesian-product expansion.
        for (const wcstring &item : var_item_list) {
            if (varexp_char_idx == 0 && var_name_and_slice_stop == insize) {
                append_completion(out, item);
            } else {
                wcstring new_in(instr, 0, varexp_char_idx);
                if (!new_in.empty()) {
                    if (new_in.back() != VARIABLE_EXPAND) {
                        new_in.push_back(INTERNAL_SEPARATOR);
                    } else if (item.empty()) {
                        new_in.push_back(VARIABLE_EXPAND_EMPTY);
                    }
                }
                new_in.append(item);
                new_in.append(instr, var_name_and_slice_stop, wcstring::npos);
                if (!expand_variables(new_in, out, varexp_char_idx, errors)) {
                    return false;
                }
            }
        }
    }
    return true;
}
Exemplo n.º 9
0
void CSSParserBorderImage::parse(const std::string &name, const std::vector<CSSToken> &tokens, std::vector<std::unique_ptr<CSSPropertyValue> > &inout_values)
{
    std::unique_ptr<CSSValueBorderImageSource> border_image_source(new CSSValueBorderImageSource());
    std::unique_ptr<CSSValueBorderImageSlice> border_image_slice(new CSSValueBorderImageSlice());
    std::unique_ptr<CSSValueBorderImageWidth> border_image_width(new CSSValueBorderImageWidth());
    std::unique_ptr<CSSValueBorderImageOutset> border_image_outset(new CSSValueBorderImageOutset());
    std::unique_ptr<CSSValueBorderImageRepeat> border_image_repeat(new CSSValueBorderImageRepeat());

    if (tokens.size() == 1 && tokens[0].type == CSSToken::type_ident && equals(tokens[0].value, "inherit"))
    {
        border_image_source->type = CSSValueBorderImageSource::type_inherit;
        border_image_slice->type = CSSValueBorderImageSlice::type_inherit;
        border_image_width->type = CSSValueBorderImageWidth::type_inherit;
        border_image_outset->type = CSSValueBorderImageOutset::type_inherit;
        border_image_repeat->type = CSSValueBorderImageRepeat::type_inherit;

        inout_values.push_back(std::move(border_image_source));
        inout_values.push_back(std::move(border_image_slice));
        inout_values.push_back(std::move(border_image_width));
        inout_values.push_back(std::move(border_image_outset));
        inout_values.push_back(std::move(border_image_repeat));

        return;
    }

    bool source_specified = false;
    bool slice_specified = false;
    bool repeat_specified = false;

    size_t pos = 0;
    do
    {
        if (!source_specified && parse_source(*border_image_source.get(), pos, tokens))
        {
            source_specified = true;
        }
        else if (!slice_specified && parse_slice(*border_image_slice.get(), pos, tokens))
        {
            slice_specified = true;

            size_t next_pos = pos;
            CSSToken token = next_token(next_pos, tokens);
            if (token.type == CSSToken::type_delim && token.value == "/")
            {
                pos = next_pos;
                if (parse_width(*border_image_width.get(), pos, tokens))
                {
                    next_pos = pos;
                    CSSToken token = next_token(next_pos, tokens);
                    if (token.type == CSSToken::type_delim && token.value == "/")
                    {
                        pos = next_pos;
                        if (!parse_outset(*border_image_outset.get(), pos, tokens))
                        {
                            return;
                        }
                    }
                }
                else if (!parse_outset(*border_image_outset.get(), pos, tokens))
                {
                    return;
                }
            }
        }
        else if (!repeat_specified && parse_repeat(*border_image_repeat.get(), pos, tokens))
        {
            repeat_specified = true;
        }
        else
        {
            return;
        }
    } while (pos != tokens.size());

    inout_values.push_back(std::move(border_image_source));
    inout_values.push_back(std::move(border_image_slice));
    inout_values.push_back(std::move(border_image_width));
    inout_values.push_back(std::move(border_image_outset));
    inout_values.push_back(std::move(border_image_repeat));
}