Esempio n. 1
0
/// Set a value in a dict. Objects are recursively expanded into their
/// vimscript equivalents. Passing 'nil' as value deletes the key.
///
/// @param dict The vimscript dict
/// @param key The key
/// @param value The new value
/// @param[out] err Details of an error that may have occurred
/// @return the old value, if any
Object dict_set_value(dict_T *dict, String key, Object value, Error *err)
{
  Object rv = OBJECT_INIT;

  if (dict->dv_lock) {
    set_api_error("Dictionary is locked", err);
    return rv;
  }

  if (key.size == 0) {
    set_api_error("Empty dictionary keys aren't allowed", err);
    return rv;
  }

  if (key.size > INT_MAX) {
    set_api_error("Key length is too high", err);
    return rv;
  }

  dictitem_T *di = dict_find(dict, (uint8_t *)key.data, (int)key.size);

  if (value.type == kObjectTypeNil) {
    // Delete the key
    if (di == NULL) {
      // Doesn't exist, fail
      set_api_error("Key doesn't exist", err);
    } else {
      // Return the old value
      rv = vim_to_object(&di->di_tv);
      // Delete the entry
      hashitem_T *hi = hash_find(&dict->dv_hashtab, di->di_key);
      hash_remove(&dict->dv_hashtab, hi);
      dictitem_free(di);
    }
  } else {
    // Update the key
    typval_T tv;

    // Convert the object to a vimscript type in the temporary variable
    if (!object_to_vim(value, &tv, err)) {
      return rv;
    }

    if (di == NULL) {
      // Need to create an entry
      di = dictitem_alloc((uint8_t *) key.data);
      dict_add(dict, di);
    } else {
      // Return the old value
      clear_tv(&di->di_tv);
    }

    // Update the value
    copy_tv(&tv, &di->di_tv);
    // Clear the temporary variable
    clear_tv(&tv);
  }

  return rv;
}
Esempio n. 2
0
File: vim.c Progetto: DINKIN/neovim
/// Call the given function with the given arguments stored in an array.
///
/// @param fname Function to call
/// @param args Functions arguments packed in an Array
/// @param[out] err Details of an error that may have occurred
/// @return Result of the function call
Object vim_call_function(String fname, Array args, Error *err)
{
  Object rv = OBJECT_INIT;
  if (args.size > MAX_FUNC_ARGS) {
    api_set_error(err, Validation,
      _("Function called with too many arguments."));
    return rv;
  }

  // Convert the arguments in args from Object to typval_T values
  typval_T vim_args[MAX_FUNC_ARGS + 1];
  size_t i = 0;  // also used for freeing the variables
  for (; i < args.size; i++) {
    if (!object_to_vim(args.items[i], &vim_args[i], err)) {
      goto free_vim_args;
    }
  }

  try_start();
  // Call the function
  typval_T rettv;
  int dummy;
  int r = call_func((char_u *) fname.data, (int) fname.size,
                    &rettv, (int) args.size, vim_args,
                    curwin->w_cursor.lnum, curwin->w_cursor.lnum, &dummy,
                    true,
                    NULL);
  if (r == FAIL) {
    api_set_error(err, Exception, _("Error calling function."));
  }
  if (!try_end(err)) {
    rv = vim_to_object(&rettv);
  }
  clear_tv(&rettv);

free_vim_args:
  while (i > 0) {
    clear_tv(&vim_args[--i]);
  }

  return rv;
}
Esempio n. 3
0
/// Copies a C string into a String (binary safe string, characters + length).
/// The resulting string is also NUL-terminated, to facilitate interoperating
/// with code using C strings.
///
/// @param str the C string to copy
/// @return the resulting String, if the input string was NULL, an
///         empty String is returned
String cstr_to_string(const char *str)
{
    if (str == NULL) {
        return (String) STRING_INIT;
    }

    size_t len = strlen(str);
    return (String) {
        .data = xmemdupz(str, len),
        .size = len
    };
}

static bool object_to_vim(Object obj, typval_T *tv, Error *err)
{
  tv->v_type = VAR_UNKNOWN;
  tv->v_lock = 0;

  switch (obj.type) {
    case kObjectTypeNil:
      tv->v_type = VAR_NUMBER;
      tv->vval.v_number = 0;
      break;

    case kObjectTypeBoolean:
      tv->v_type = VAR_NUMBER;
      tv->vval.v_number = obj.data.boolean;
      break;

    case kObjectTypeInteger:
      if (obj.data.integer > INT_MAX || obj.data.integer < INT_MIN) {
        set_api_error("Integer value outside range", err);
        return false;
      }

      tv->v_type = VAR_NUMBER;
      tv->vval.v_number = (int)obj.data.integer;
      break;

    case kObjectTypeFloat:
      tv->v_type = VAR_FLOAT;
      tv->vval.v_float = obj.data.floating;
      break;

    case kObjectTypeString:
      tv->v_type = VAR_STRING;
      tv->vval.v_string = xmemdupz(obj.data.string.data,
                                   obj.data.string.size);
      break;

    case kObjectTypeArray:
      tv->v_type = VAR_LIST;
      tv->vval.v_list = list_alloc();

      for (uint32_t i = 0; i < obj.data.array.size; i++) {
        Object item = obj.data.array.items[i];
        listitem_T *li = listitem_alloc();

        if (!object_to_vim(item, &li->li_tv, err)) {
          // cleanup
          listitem_free(li);
          list_free(tv->vval.v_list, true);
          return false;
        }

        list_append(tv->vval.v_list, li);
      }
      tv->vval.v_list->lv_refcount++;
      break;

    case kObjectTypeDictionary:
      tv->v_type = VAR_DICT;
      tv->vval.v_dict = dict_alloc();

      for (uint32_t i = 0; i < obj.data.dictionary.size; i++) {
        KeyValuePair item = obj.data.dictionary.items[i];
        String key = item.key;

        if (key.size == 0) {
          set_api_error("Empty dictionary keys aren't allowed", err);
          // cleanup
          dict_free(tv->vval.v_dict, true);
          return false;
        }

        dictitem_T *di = dictitem_alloc((uint8_t *) key.data);

        if (!object_to_vim(item.value, &di->di_tv, err)) {
          // cleanup
          dictitem_free(di);
          dict_free(tv->vval.v_dict, true);
          return false;
        }

        dict_add(tv->vval.v_dict, di);
      }
      tv->vval.v_dict->dv_refcount++;
      break;
  }

  return true;
}
Esempio n. 4
0
/// Copies a C string into a String (binary safe string, characters + length).
/// The resulting string is also NUL-terminated, to facilitate interoperating
/// with code using C strings.
///
/// @param str the C string to copy
/// @return the resulting String, if the input string was NULL, an
///         empty String is returned
String cstr_to_string(const char *str)
{
    if (str == NULL) {
        return (String) STRING_INIT;
    }

    size_t len = strlen(str);
    return (String) {
        .data = xmemdupz(str, len),
        .size = len
    };
}

/// Creates a String using the given C string. Unlike
/// cstr_to_string this function DOES NOT copy the C string.
///
/// @param str the C string to use
/// @return The resulting String, or an empty String if
///           str was NULL
String cstr_as_string(char *str) FUNC_ATTR_PURE
{
  if (str == NULL) {
    return (String) STRING_INIT;
  }
  return (String) {.data = str, .size = strlen(str)};
}

bool object_to_vim(Object obj, typval_T *tv, Error *err)
{
  tv->v_type = VAR_UNKNOWN;
  tv->v_lock = 0;

  switch (obj.type) {
    case kObjectTypeNil:
      tv->v_type = VAR_NUMBER;
      tv->vval.v_number = 0;
      break;

    case kObjectTypeBoolean:
      tv->v_type = VAR_NUMBER;
      tv->vval.v_number = obj.data.boolean;
      break;

    case kObjectTypeInteger:
      if (obj.data.integer > INT_MAX || obj.data.integer < INT_MIN) {
        api_set_error(err, Validation, _("Integer value outside range"));
        return false;
      }

      tv->v_type = VAR_NUMBER;
      tv->vval.v_number = (int)obj.data.integer;
      break;

    case kObjectTypeFloat:
      tv->v_type = VAR_FLOAT;
      tv->vval.v_float = obj.data.floating;
      break;

    case kObjectTypeString:
      tv->v_type = VAR_STRING;
      tv->vval.v_string = xmemdupz(obj.data.string.data,
                                   obj.data.string.size);
      break;

    case kObjectTypeArray:
      tv->v_type = VAR_LIST;
      tv->vval.v_list = list_alloc();

      for (uint32_t i = 0; i < obj.data.array.size; i++) {
        Object item = obj.data.array.items[i];
        listitem_T *li = listitem_alloc();

        if (!object_to_vim(item, &li->li_tv, err)) {
          // cleanup
          listitem_free(li);
          list_free(tv->vval.v_list, true);
          return false;
        }

        list_append(tv->vval.v_list, li);
      }
      tv->vval.v_list->lv_refcount++;
      break;

    case kObjectTypeDictionary:
      tv->v_type = VAR_DICT;
      tv->vval.v_dict = dict_alloc();

      for (uint32_t i = 0; i < obj.data.dictionary.size; i++) {
        KeyValuePair item = obj.data.dictionary.items[i];
        String key = item.key;

        if (key.size == 0) {
          api_set_error(err,
                        Validation,
                        _("Empty dictionary keys aren't allowed"));
          // cleanup
          dict_free(tv->vval.v_dict, true);
          return false;
        }

        dictitem_T *di = dictitem_alloc((uint8_t *) key.data);

        if (!object_to_vim(item.value, &di->di_tv, err)) {
          // cleanup
          dictitem_free(di);
          dict_free(tv->vval.v_dict, true);
          return false;
        }

        dict_add(tv->vval.v_dict, di);
      }
      tv->vval.v_dict->dv_refcount++;
      break;
    default:
      abort();
  }

  return true;
}