int Option::parse_value(
  const std::string& raw_val,
  value_t *out,
  std::string *error_message,
  std::string *normalized_value) const
{
  std::string val = raw_val;

  int r = pre_validate(&val, error_message);
  if (r != 0) {
    return r;
  }

  if (type == Option::TYPE_INT) {
    int64_t f = strict_si_cast<int64_t>(val.c_str(), error_message);
    if (!error_message->empty()) {
      return -EINVAL;
    }
    *out = f;
  } else if (type == Option::TYPE_UINT) {
    uint64_t f = strict_si_cast<uint64_t>(val.c_str(), error_message);
    if (!error_message->empty()) {
      return -EINVAL;
    }
    *out = f;
  } else if (type == Option::TYPE_STR) {
    *out = val;
  } else if (type == Option::TYPE_FLOAT) {
    double f = strict_strtod(val.c_str(), error_message);
    if (!error_message->empty()) {
      return -EINVAL;
    } else {
      *out = f;
    }
  } else if (type == Option::TYPE_BOOL) {
    if (strcasecmp(val.c_str(), "false") == 0) {
      *out = false;
    } else if (strcasecmp(val.c_str(), "true") == 0) {
      *out = true;
    } else {
      int b = strict_strtol(val.c_str(), 10, error_message);
      if (!error_message->empty()) {
	return -EINVAL;
      }
      *out = (bool)!!b;
    }
  } else if (type == Option::TYPE_ADDR) {
    entity_addr_t addr;
    if (!addr.parse(val.c_str())){
      return -EINVAL;
    }
    *out = addr;
  } else if (type == Option::TYPE_UUID) {
    uuid_d uuid;
    if (!uuid.parse(val.c_str())) {
      return -EINVAL;
    }
    *out = uuid;
  } else if (type == Option::TYPE_SIZE) {
    Option::size_t sz{strict_iecstrtoll(val.c_str(), error_message)};
    if (!error_message->empty()) {
      return -EINVAL;
    }
    *out = sz;
  } else if (type == Option::TYPE_SECS) {
    try {
      *out = parse_duration(val);
    } catch (const invalid_argument&) {
      return -EINVAL;
    }
  } else {
    ceph_abort();
  }

  r = validate(*out, error_message);
  if (r != 0) {
    return r;
  }

  if (normalized_value) {
    *normalized_value = to_str(*out);
  }
  return 0;
}
int Option::parse_value(
  const std::string& raw_val,
  value_t *out,
  std::string *error_message,
  std::string *normalized_value) const
{
  std::string val = raw_val;

  int r = pre_validate(&val, error_message);
  if (r != 0) {
    return r;
  }

  if (type == Option::TYPE_INT) {
    int64_t f = strict_si_cast<int64_t>(val.c_str(), error_message);
    if (!error_message->empty()) {
      return -EINVAL;
    }
    *out = f;
  } else if (type == Option::TYPE_UINT) {
    uint64_t f = strict_si_cast<uint64_t>(val.c_str(), error_message);
    if (!error_message->empty()) {
      return -EINVAL;
    }
    *out = f;
  } else if (type == Option::TYPE_STR) {
    *out = val;
  } else if (type == Option::TYPE_FLOAT) {
    double f = strict_strtod(val.c_str(), error_message);
    if (!error_message->empty()) {
      return -EINVAL;
    } else {
      *out = f;
    }
  } else if (type == Option::TYPE_BOOL) {
    if (strcasecmp(val.c_str(), "false") == 0) {
      *out = false;
    } else if (strcasecmp(val.c_str(), "true") == 0) {
      *out = true;
    } else {
      int b = strict_strtol(val.c_str(), 10, error_message);
      if (!error_message->empty()) {
	return -EINVAL;
      }
      *out = (bool)!!b;
    }
  } else if (type == Option::TYPE_ADDR) {
    entity_addr_t addr;
    if (!addr.parse(val.c_str())){
      return -EINVAL;
    }
    *out = addr;
  } else if (type == Option::TYPE_UUID) {
    uuid_d uuid;
    if (!uuid.parse(val.c_str())) {
      return -EINVAL;
    }
    *out = uuid;
  } else if (type == Option::TYPE_SIZE) {
    Option::size_t sz{strict_iecstrtoll(val.c_str(), error_message)};
    if (!error_message->empty()) {
      return -EINVAL;
    }
    *out = sz;
  } else if (type == Option::TYPE_SECS) {
    try {
      *out = parse_duration(val);
    } catch (const invalid_argument&) {
      return -EINVAL;
    }
  } else {
    ceph_abort();
  }

  r = validate(*out, error_message);
  if (r != 0) {
    return r;
  }

  if (normalized_value) {
    *normalized_value = to_str(*out);
  }
  return 0;
}