settings.c 7.97 KB
Newer Older
1
/* SPDX-License-Identifier: Zlib */
2 3

#include <stdlib.h>
4
#include <glib.h>
5
#include <glib/gi18n-lib.h>
Sebastian Ramacher's avatar
Sebastian Ramacher committed
6
#include <string.h>
7 8 9
#ifdef WITH_JSON
#include <json.h>
#endif
10

Sebastian Ramacher's avatar
Sebastian Ramacher committed
11 12 13 14
#include "settings.h"
#include "datastructures.h"
#include "completion.h"
#include "session.h"
15
#include "internal.h"
16
#include "utils.h"
17

18 19 20 21
/**
 * Structure of a settings entry
 */
struct girara_setting_s
22
{
23 24 25 26 27 28 29 30 31 32 33 34
  char* name; /**< Name of the setting */
  union
  {
    bool b; /**< Boolean */
    int i; /**< Integer */
    float f; /**< Floating number */
    char *s; /**< String */
  } value; /**< Value of the setting */
  girara_setting_type_t type; /**< Type identifier */
  bool init_only; /**< Option can be set only before girara gets initialized */
  char* description; /**< Description of this setting */
  girara_setting_callback_t callback; /**< Callback that gets executed when the value of the setting changes */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
35
  void* data; /**< Arbitrary data that can be used by callbacks */
36 37 38
};

void
Sebastian Ramacher's avatar
Sebastian Ramacher committed
39
girara_setting_set_value(girara_session_t* session, girara_setting_t* setting, const void* value)
40 41 42
{
  g_return_if_fail(setting && (value || setting->type == STRING));

43 44
  switch(setting->type) {
    case BOOLEAN:
Sebastian Ramacher's avatar
Sebastian Ramacher committed
45
      setting->value.b = *((const bool *) value);
46 47
      break;
    case FLOAT:
Sebastian Ramacher's avatar
Sebastian Ramacher committed
48
      setting->value.f = *((const float *) value);
49 50
      break;
    case INT:
Sebastian Ramacher's avatar
Sebastian Ramacher committed
51
      setting->value.i = *((const int *) value);
52 53 54 55 56 57 58 59 60 61
      break;
    case STRING:
      if (setting->value.s != NULL) {
        g_free(setting->value.s);
      }
      setting->value.s = value ? g_strdup(value) : NULL;
      break;
    default:
      g_assert(false);
  }
62 63 64 65

  if (session && setting->callback != NULL) {
    setting->callback(session, setting->name, setting->type, value, setting->data);
  }
66
}
67 68

bool
69
girara_setting_add(girara_session_t* session, const char* name, void* value, girara_setting_type_t type, bool init_only, const char* description, girara_setting_callback_t callback, void* data)
70
{
71 72
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(name != NULL, false);
73
  g_return_val_if_fail(type != UNKNOWN, false);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
74 75 76
  if (type != STRING && value == NULL) {
    return false;
  }
77 78

  /* search for existing setting */
79 80 81
  if (girara_setting_find(session, name) != NULL) {
    return false;
  }
82 83

  /* add new setting */
84
  girara_setting_t* setting = g_slice_new0(girara_setting_t);
85 86 87 88 89 90

  setting->name        = g_strdup(name);
  setting->type        = type;
  setting->init_only   = init_only;
  setting->description = description ? g_strdup(description) : NULL;
  setting->callback    = callback;
91
  setting->data        = data;
92
  girara_setting_set_value(NULL, setting, value);
93

94
  girara_list_append(session->private_data->settings, setting);
95 96

  return true;
97 98 99
}

bool
Sebastian Ramacher's avatar
Sebastian Ramacher committed
100
girara_setting_set(girara_session_t* session, const char* name, const void* value)
101
{
102 103
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(name != NULL, false);
104

105 106 107 108
  girara_setting_t* setting = girara_setting_find(session, name);
  if (setting == NULL) {
    return false;
  }
109

110
  girara_setting_set_value(session, setting, value);
111
  return true;
112 113
}

114 115
bool
girara_setting_get_value(girara_setting_t* setting, void* dest)
116
{
117
  g_return_val_if_fail(setting != NULL && dest != NULL, false);
118 119 120

  switch(setting->type) {
    case BOOLEAN:
Sebastian Ramacher's avatar
Sebastian Ramacher committed
121 122
    {
      bool *bvalue = (bool *)dest;
123
      *bvalue = setting->value.b;
124
      break;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
125
    }
126
    case FLOAT:
Sebastian Ramacher's avatar
Sebastian Ramacher committed
127 128
    {
      float *fvalue = (float *)dest;
129
      *fvalue = setting->value.f;
130
      break;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
131
    }
132
    case INT:
Sebastian Ramacher's avatar
Sebastian Ramacher committed
133 134
    {
      int   *ivalue = (int*) dest;
135
      *ivalue = setting->value.i;
136
      break;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
137
    }
138
    case STRING:
Sebastian Ramacher's avatar
Sebastian Ramacher committed
139 140
    {
      char **svalue = (char**) dest;
141 142
      *svalue = setting->value.s ? g_strdup(setting->value.s) : NULL;
      break;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
143
    }
144 145
    default:
      g_assert(false);
146
  }
147

148
  return true;
149
}
150

151 152
bool
girara_setting_get(girara_session_t* session, const char* name, void* dest)
153
{
154
  g_return_val_if_fail(session != NULL && name != NULL && dest != NULL, false);
155 156 157

  girara_setting_t* setting = girara_setting_find(session, name);
  if (setting == NULL) {
158
    return false;
159 160
  }

161
  return girara_setting_get_value(setting, dest);
162 163
}

164 165 166 167 168 169 170 171 172 173 174 175 176 177
void
girara_setting_free(girara_setting_t* setting)
{
  if (!setting) {
    return;
  }

  g_free(setting->name);
  g_free(setting->description);
  if (setting->type == STRING) {
    g_free(setting->value.s);
  }
  g_slice_free(girara_setting_t, setting);
}
Sebastian Ramacher's avatar
Sebastian Ramacher committed
178

179 180 181 182 183 184 185
girara_setting_t*
girara_setting_find(girara_session_t* session, const char* name)
{
  g_return_val_if_fail(session != NULL, NULL);
  g_return_val_if_fail(name != NULL, NULL);

  girara_setting_t* result = NULL;
Sebastian Ramacher's avatar
Sebastian Ramacher committed
186
  GIRARA_LIST_FOREACH_BODY(session->private_data->settings, girara_setting_t*, setting,
187 188 189 190
    if (g_strcmp0(setting->name, name) == 0) {
      result = setting;
      break;
    }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
191
  );
192 193 194 195

  return result;
}

196
const char*
197
girara_setting_get_name(const girara_setting_t* setting) {
198 199 200 201
  g_return_val_if_fail(setting, NULL);
  return setting->name;
}

202 203 204 205 206 207
girara_setting_type_t
girara_setting_get_type(girara_setting_t* setting) {
  g_return_val_if_fail(setting, UNKNOWN);
  return setting->type;
}

Sebastian Ramacher's avatar
Sebastian Ramacher committed
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
girara_completion_t*
girara_cc_set(girara_session_t* session, const char* input)
{
  if (input == NULL) {
    return NULL;
  }

  girara_completion_t* completion  = girara_completion_init();
  if (completion == NULL) {
    return NULL;
  }
  girara_completion_group_t* group = girara_completion_group_create(session, NULL);
  if (group == NULL) {
    girara_completion_free(completion);
    return NULL;
  }
  girara_completion_add_group(completion, group);

  unsigned int input_length = strlen(input);

Sebastian Ramacher's avatar
Sebastian Ramacher committed
228
  GIRARA_LIST_FOREACH_BODY(session->private_data->settings, girara_setting_t*, setting,
Sebastian Ramacher's avatar
Sebastian Ramacher committed
229 230 231 232
    if ((setting->init_only == false) && (input_length <= strlen(setting->name)) &&
        !strncmp(input, setting->name, input_length)) {
      girara_completion_group_add_element(group, setting->name, setting->description);
    }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
233
  );
Sebastian Ramacher's avatar
Sebastian Ramacher committed
234 235 236

  return completion;
}
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257

#ifdef WITH_JSON
bool
girara_cmd_dump_config(girara_session_t* session, girara_list_t* argument_list)
{
  if (session == NULL || argument_list == NULL) {
    return false;
  }

  const size_t number_of_arguments = girara_list_size(argument_list);
  if (number_of_arguments != 1) {
    girara_warning("Invalid number of arguments passed: %zu instead of 1",
        number_of_arguments);
    girara_notify(session, GIRARA_ERROR,
        _("Invalid number of arguments passed: %zu instead of 1"),
        number_of_arguments);
    return false;
  }

  json_object* json_config = json_object_new_object();

Sebastian Ramacher's avatar
Sebastian Ramacher committed
258
  GIRARA_LIST_FOREACH_BODY(session->private_data->settings, girara_setting_t*, setting,
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
    json_object* json_setting = json_object_new_object();

    json_object* json_value = NULL;
    json_object* json_type = NULL;
    switch(setting->type) {
      case BOOLEAN:
        json_value = json_object_new_boolean(setting->value.b);
        json_type = json_object_new_string("boolean");
        break;
      case FLOAT:
        json_value = json_object_new_double(setting->value.f);
        json_type = json_object_new_string("float");
        break;
      case INT:
        json_value = json_object_new_int(setting->value.i);
        json_type = json_object_new_string("int");
        break;
      case STRING:
        json_value = json_object_new_string(setting->value.s ? setting->value.s : "");
        json_type = json_object_new_string("string");
        break;
      default:
        girara_debug("Invalid setting: %s", setting->name);
    }
    if (json_value != NULL) {
      json_object_object_add(json_setting, "value", json_value);
      json_object_object_add(json_setting, "type", json_type);
    }

    if (setting->description != NULL) {
      json_object_object_add(json_setting, "description",
          json_object_new_string(setting->description));
    }
    json_object_object_add(json_setting, "init-only",
        json_object_new_boolean(setting->init_only));

    json_object_object_add(json_config, setting->name, json_setting);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
296
  );
297 298 299 300 301 302 303 304

  json_object_to_file_ext(girara_list_nth(argument_list, 0), json_config,
      JSON_C_TO_STRING_PRETTY);
  json_object_put(json_config);

  return true;
}
#endif