#ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include "Ecore_Config.h" #include "Ecore.h" #include "ecore_config_private.h" typedef struct __Ecore_Config_Arg_Callback _Ecore_Config_Arg_Callback; struct __Ecore_Config_Arg_Callback { char short_opt; char *long_opt; char *description; void *data; void (*func)(char *val, void *data); Ecore_Config_Type type; _Ecore_Config_Arg_Callback *next; }; char *__ecore_config_app_description; _Ecore_Config_Arg_Callback *_ecore_config_arg_callbacks; /* shorthand prop setup code to make client apps a little smaller ;) */ /** * Creates a new property, if it does not already exist, and sets its * attributes to those given. * * The type of the property is guessed from the key and the value * given. * * @param key The property key. * @param val Pointer to default value of key. * @param short_opt Short option used to set the property from command * line. * @param long_opt Long option used to set the property from command line. * @param desc String description of property. * @return @c ECORE_CONFIG_ERR_SUCC on success. * @ingroup Ecore_Config_Create_Group */ int ecore_config_create(const char *key, void *val, char short_opt, char *long_opt, char *desc) { int type = ecore_config_type_guess(key, val); return ecore_config_typed_create(key, val, type, short_opt, long_opt, desc); } /** * Creates a new property, if it does not already exist, and sets its * attributes to those given. * @param key The property key. * @param val Pointer to default value of key. * @param type Type of the property. * @param short_opt Short option used to set the property from * command line. * @param long_opt Long option used to set the property from command line. * @param desc String description of property. * @return @c ECORE_CONFIG_ERR_SUCC on success. * @ingroup Ecore_Config_Create_Group */ int ecore_config_typed_create(const char *key, void *val, int type, char short_opt, char *long_opt, char *desc) { int ret; if ((ret = ecore_config_typed_default(key, val, type)) != ECORE_CONFIG_ERR_SUCC) return ret; if ((ret = ecore_config_short_opt_set(key, short_opt)) != ECORE_CONFIG_ERR_SUCC) return ret; if ((ret = ecore_config_long_opt_set(key, long_opt)) != ECORE_CONFIG_ERR_SUCC) return ret; ret = ecore_config_describe(key, desc); return ret; } /** * Creates a new boolean property, if it does not already exist, and sets its * attributes to those given. * @param key The property key. * @param val Default boolean value of key. * @param short_opt Short option used to set the property from command * line. * @param long_opt Long option used to set the property from command line. * @param desc String description of property. * @return @c ECORE_CONFIG_ERR_SUCC on success. * @ingroup Ecore_Config_Create_Group */ int ecore_config_boolean_create(const char *key, int val, char short_opt, char *long_opt, char *desc) { return ecore_config_typed_create(key, (void *)&val, ECORE_CONFIG_BLN, short_opt, long_opt, desc); } /** * Creates a new integer property, if it does not already exist, and sets its * attributes to those given. * @param key The property key. * @param val Default integer value of key. * @param short_opt Short option used to set the property from command * line. * @param long_opt Long option used to set the property from command line. * @param desc String description of property. * @return @c ECORE_CONFIG_ERR_SUCC on success. * @ingroup Ecore_Config_Create_Group */ int ecore_config_int_create(const char *key, int val, char short_opt, char *long_opt, char *desc) { return ecore_config_typed_create(key, (void *)&val, ECORE_CONFIG_INT, short_opt, long_opt, desc); } /** * Creates a new integer property, if it does not already exist, and sets its * attributes to those given. * @param key The property key. * @param val Default integer value of key. * @param low Lowest valid integer value for the property. * @param high Highest valid integer value for the property. * @param step Increment value for the property. * @param short_opt Short option used to set the property from command * line. * @param long_opt Long option used to set the property from command line. * @param desc String description of property. * @return @c ECORE_CONFIG_ERR_SUCC on success. * @ingroup Ecore_Config_Create_Group */ int ecore_config_int_create_bound(const char *key, int val, int low, int high, int step, char short_opt, char *long_opt, char *desc) { Ecore_Config_Prop *e; int ret; ret = ecore_config_typed_create(key, (void *)&val, ECORE_CONFIG_INT, short_opt, long_opt, desc); if (ret != ECORE_CONFIG_ERR_SUCC) return ret; e = ecore_config_get(key); if (e) { e->step = step; e->flags |= ECORE_CONFIG_FLAG_BOUNDS; e->lo = low; e->hi = high; ecore_config_bound(e); } return ret; } /** * Creates a new string property, if it does not already exist, and sets its * attributes to those given. * @param key The property key. * @param val Default value of key. * @param short_opt Short option used to set the property from command * line. * @param long_opt Long option used to set the property from command line. * @param desc String description of property. * @return @c ECORE_CONFIG_ERR_SUCC on success. * @ingroup Ecore_Config_Create_Group */ int ecore_config_string_create(const char *key, char *val, char short_opt, char *long_opt, char *desc) { return ecore_config_typed_create(key, (void *)val, ECORE_CONFIG_STR, short_opt, long_opt, desc); } /** * Creates a new float property, if it does not already exist, and sets its * attributes to those given. * @param key The property key. * @param val Default float value of key. * @param short_opt Short option used to set the property from command * line. * @param long_opt Long option used to set the property from command line. * @param desc String description of property. * @return @c ECORE_CONFIG_ERR_SUCC on success. * @ingroup Ecore_Config_Create_Group */ int ecore_config_float_create(const char *key, float val, char short_opt, char *long_opt, char *desc) { return ecore_config_typed_create(key, (void *)&val, ECORE_CONFIG_FLT, short_opt, long_opt, desc); } /** * Creates a new float property, if it does not already exist, and sets its * attributes to those given. * @param key The property key. * @param val Default float value of key. * @param low Lowest valid float value for the property. * @param high Highest valid float value for the property. * @param step Increment value for the property. * @param short_opt Short option used to set the property from command * line. * @param long_opt Long option used to set the property from command line. * @param desc String description of property. * @return @c ECORE_CONFIG_ERR_SUCC on success. * @ingroup Ecore_Config_Create_Group */ int ecore_config_float_create_bound(const char *key, float val, float low, float high, float step, char short_opt, char *long_opt, char *desc) { Ecore_Config_Prop *e; int ret; ret = ecore_config_typed_create(key, (void *)&val, ECORE_CONFIG_FLT, short_opt, long_opt, desc); e = ecore_config_get(key); if (e) { e->step = (int)(step * ECORE_CONFIG_FLOAT_PRECISION); e->flags |= ECORE_CONFIG_FLAG_BOUNDS; e->lo = (int)(low * ECORE_CONFIG_FLOAT_PRECISION); e->hi = (int)(high * ECORE_CONFIG_FLOAT_PRECISION); ecore_config_bound(e); } return ret; } /** * Creates a new color property, if it does not already exist, and sets its * attributes to those given. * @param key The property key. * @param val Default color value of key, as a hexadecimal string. * @param short_opt Short option used to set the property from command * line. * @param long_opt Long option used to set the property from command line. * @param desc String description of property. * @return @c ECORE_CONFIG_ERR_SUCC on success. * @ingroup Ecore_Config_Create_Group */ int ecore_config_argb_create(const char *key, char *val, char short_opt, char *long_opt, char *desc) { return ecore_config_typed_create(key, (void *)val, ECORE_CONFIG_RGB, short_opt, long_opt, desc); } /** * Creates a new theme property, if it does not already exist, and sets its * attributes to those given. * @param key The property key. * @param val Default theme name for the property. * @param short_opt Short option used to set the property from command * line. * @param long_opt Long option used to set the property from command line. * @param desc String description of property. * @return @c ECORE_CONFIG_ERR_SUCC on success. * @ingroup Ecore_Config_Create_Group */ int ecore_config_theme_create(const char *key, char *val, char short_opt, char *long_opt, char *desc) { return ecore_config_typed_create(key, (void *)val, ECORE_CONFIG_THM, short_opt, long_opt, desc); } /* this should only be built if evas is present */ /** * Calls evas_font_path_append on @p evas for each of the font names stored * in the property "/e/font/path". * @param evas Evas object to append the font names to. * @return @c ECORE_CONFIG_ERR_SUCC on success. @c ECORE_CONFIG_ERR_NODATA * is returned if the property has not been set. */ int ecore_config_evas_font_path_apply(Evas * evas) { char *font_path, *font_path_tmp, *ptr, *end; font_path = ecore_config_string_get("/e/font/path"); if (!font_path) return ECORE_CONFIG_ERR_NODATA; ptr = font_path; end = font_path + strlen(font_path); font_path_tmp = font_path; while (ptr && ptr < end) { while (*ptr != '|' && ptr < end) ptr++; if (ptr < end) *ptr = '\0'; evas_font_path_append(evas, font_path_tmp); ptr++; font_path_tmp = ptr; } free(font_path); return ECORE_CONFIG_ERR_SUCC; } /** * Retrieves the default theme search path. * * @return The default theme search path. */ char * ecore_config_theme_default_path_get(void) { char *path, *home; int len; home = getenv("HOME"); len = strlen(PACKAGE_DATA_DIR "/../") + strlen(__ecore_config_app_name) + strlen("/themes/") + 1; if (home) len += strlen(home) + strlen("/.e/apps/") + strlen(__ecore_config_app_name) + strlen("/themes/|"); /* no \0, as that is above */ if (!(path = malloc(len))) return NULL; *path = '\0'; if (home) { strcat(path, home); strcat(path, "/.e/apps/"); strcat(path, __ecore_config_app_name); strcat(path, "/themes/|"); } strcat(path, PACKAGE_DATA_DIR "/../"); strcat(path, __ecore_config_app_name); strcat(path, "/themes/"); return path; } /** * Retrieves the search path used to find themes. * * The search path is stored in the property "/e/themes/search_path". If * the property has not been set, the default path used is * "/usr/local/share//themes|~/.e/apps//themes". * See @ref ecore_config_theme_default_path_get for more information about * the default path. * * @return The search path. @c NULL is returned if there is no memory left. */ char * ecore_config_theme_search_path_get(void) { char *search_path; search_path = ecore_config_string_get("/e/themes/search_path"); /* this should no longer be the case, as it is defaulted in init */ if (!search_path) { search_path = ecore_config_theme_default_path_get(); if (search_path) { ecore_config_string_default("/e/themes/search_path", search_path); free(search_path); } } return search_path; } /** * Adds the given path to the search path used to find themes. * * If the search path is successfully, the new search path will be saved * into the property "/e/themes/search_path". Therefore, this function * should be called @b after @ref ecore_config_load to allow a user to * override the default search path. * * @param path The given * @return @c ECORE_CONFIG_ERR_SUCC on success. @c ECORE_CONFIG_ERR_FAIL * will be returned if @p path already exists in the search path. * @c ECORE_CONFIG_ERR_FAIL is returned if @p path is @c NULL. */ int ecore_config_theme_search_path_append(const char *path) { char *search_path, *loc, *new_search_path; int len, search_len; Ecore_Config_Prop *prop; if (!path) return ECORE_CONFIG_ERR_NODATA; search_path = ecore_config_theme_search_path_get(); loc = strstr(search_path, path); len = strlen(path); search_len = strlen(search_path); if (!loc || (loc != search_path && *(loc - 1) != '|') || (loc != (search_path + search_len - len) && *(loc + len - 1) != '|')) { new_search_path = malloc(search_len + len + 2); /* 2 = \0 + | */ strcpy(new_search_path, search_path); strncat(new_search_path, "|", 1); strncat(new_search_path, path, len); ecore_config_string_set("/e/themes/search_path", new_search_path); prop = ecore_config_get("/e/themes/search_path"); if (prop) prop->flags &= ~ECORE_CONFIG_FLAG_MODIFIED; free(new_search_path); return ECORE_CONFIG_ERR_SUCC; } return ECORE_CONFIG_ERR_FAIL; } /** * Retrieve a theme file's full path. * * The search path for theme files is given by @ref * ecore_config_theme_search_path_get . * * @param name The name of the theme. * @return A full path to the theme on success. @c NULL will be returned * if @p name is @c NULL or no theme matching the given name could * be found. */ char * ecore_config_theme_with_path_from_name_get(char *name) { char *search_path, *search_path_tmp, *ptr, *end, *file; struct stat st; if (!name) return NULL; /* no theme specified (nor a default) */ search_path = ecore_config_theme_search_path_get(); ptr = search_path; end = search_path + strlen(search_path); search_path_tmp = search_path; while (ptr && ptr < end) { while (*ptr != '|' && ptr < end) ptr++; if (ptr < end) *ptr = '\0'; file = malloc(strlen(search_path_tmp) + strlen(name) + 6); /* 6 = / + .edj + \0 */ snprintf(file, strlen(search_path_tmp) + strlen(name) + 6, "%s/%s.edj", search_path_tmp, name); if (stat(file, &st) == 0) { free(search_path); return file; } free(file); ptr++; search_path_tmp = ptr; } free(search_path); return NULL; /* we could not find the theme with that name in search path */ } /** * Retrieves the full path to the theme file of the theme stored in the * given property. * * The search path for themes is given by @ref * ecore_config_theme_search_path_get . * * @param key The given property. * @return A full path to the theme on success, or @c NULL on failure. * This function will fail if no key is specified or not theme * matching that given by the property @p key could be found. */ char * ecore_config_theme_with_path_get(const char *key) { return ecore_config_theme_with_path_from_name_get(ecore_config_theme_get(key)); } static const char *_ecore_config_short_types[] = { " ", " ", " ", " ", " ", " ", "" }; /** * Prints the property list of the local configuration bundle to output. */ void ecore_config_args_display(void) { Ecore_Config_Prop *props; _Ecore_Config_Arg_Callback *callbacks; if (__ecore_config_app_description) ERR("%s\n\n", __ecore_config_app_description); ERR("Supported Options:"); ERR(" -h, --help\t Print this text"); if (!__ecore_config_bundle_local) return; props = __ecore_config_bundle_local->data; while (props) { /* if it is a system prop, or cannot be set on command line hide it */ if (props->flags & ECORE_CONFIG_FLAG_SYSTEM || (!props->short_opt && !props->long_opt)) { props = props->next; continue; } INF(" %c%c%c --%s\t%s %s", props->short_opt ? '-' : ' ', props->short_opt ? props->short_opt : ' ', props->short_opt ? ',' : ' ', props->long_opt ? props->long_opt : props->key, _ecore_config_short_types[props->type], props->description ? props->description : "(no description available)"); props = props->next; } callbacks = _ecore_config_arg_callbacks; while (callbacks) { INF(" %c%c%c --%s\t%s %s", callbacks->short_opt ? '-' : ' ', callbacks->short_opt ? callbacks->short_opt : ' ', callbacks->short_opt ? ',' : ' ', callbacks->long_opt ? callbacks->long_opt : "", _ecore_config_short_types[callbacks->type], callbacks->description ? callbacks->description : "(no description available)"); callbacks = callbacks->next; } } static int ecore_config_parse_set(Ecore_Config_Prop * prop, char *arg, char *opt, char opt2) { if (!arg) { if (opt) ERR("Missing expected argument for option --%s", opt); else ERR("Missing expected argument for option -%c", opt2); return ECORE_CONFIG_PARSE_EXIT; } else { ecore_config_set(prop->key, arg); prop->flags |= ECORE_CONFIG_FLAG_CMDLN; } return ECORE_CONFIG_PARSE_CONTINUE; } static void ecore_config_args_callback_add(char short_opt, char *long_opt, char *desc, void (*func)(char *val, void *data), void *data, Ecore_Config_Type type) { _Ecore_Config_Arg_Callback *new_cb; new_cb = malloc(sizeof(_Ecore_Config_Arg_Callback)); new_cb->short_opt = short_opt; if (long_opt) new_cb->long_opt = strdup(long_opt); if (desc) new_cb->description = strdup(desc); new_cb->data = data; new_cb->func = func; new_cb->type = type; new_cb->next = _ecore_config_arg_callbacks; _ecore_config_arg_callbacks = new_cb; } void ecore_config_args_callback_str_add(char short_opt, char *long_opt, char *desc, void (*func)(char *val, void *data), void *data) { ecore_config_args_callback_add(short_opt, long_opt, desc, func, data, ECORE_CONFIG_STR); } void ecore_config_args_callback_noarg_add(char short_opt, char *long_opt, char *desc, void (*func)(char *val, void *data), void *data) { ecore_config_args_callback_add(short_opt, long_opt, desc, func, data, ECORE_CONFIG_NIL); } /** * Parse the arguments set by @ref ecore_app_args_set and set properties * accordingly. * * @return @c ECORE_CONFIG_PARSE_CONTINUE if successful. * @c ECORE_CONFIG_PARSE_EXIT is returned if an unrecognised option * is found. @c ECORE_CONFIG_PARSE_HELP is returned if help was * displayed. */ int ecore_config_args_parse(void) { int argc; char **argv; int nextarg, next_short_opt, found, ret; char *arg; char *long_opt, short_opt; Ecore_Config_Prop *prop; _Ecore_Config_Arg_Callback *callback; ecore_app_args_get(&argc, &argv); nextarg = 1; while (nextarg < argc) { arg = argv[nextarg]; if (*arg != '-') { ERR("Unexpected attribute \"%s\"", arg); nextarg++; continue; } next_short_opt = 1; short_opt = *(arg + next_short_opt); if (short_opt == '-') { long_opt = arg + 2; if (!strcmp(long_opt, "help")) { ecore_config_args_display(); return ECORE_CONFIG_PARSE_HELP; } found = 0; prop = __ecore_config_bundle_local->data; while (prop) { if ((prop->long_opt && !strcmp(long_opt, prop->long_opt)) || !strcmp(long_opt, prop->key)) { found = 1; if ((ret = ecore_config_parse_set(prop, argv[++nextarg], long_opt, '\0')) != ECORE_CONFIG_PARSE_CONTINUE) return ret; break; } prop = prop->next; } if (!found) { callback = _ecore_config_arg_callbacks; while (callback) { if ((callback->long_opt && !strcmp(long_opt, callback->long_opt))) { found = 1; if (callback->type == ECORE_CONFIG_NIL) { callback->func(NULL, callback->data); } else { if (!argv[++nextarg]) { ERR("Missing expected argument for option --%s", long_opt); return ECORE_CONFIG_PARSE_EXIT; } callback->func(argv[nextarg], callback->data); } break; } callback = callback->next; } } if (!found) { ERR("Unrecognised option \"%s\"", long_opt); ERR("Try using -h or --help for more information.\n"); return ECORE_CONFIG_PARSE_EXIT; } } else { while (short_opt) { if (short_opt == 'h') { ecore_config_args_display(); return ECORE_CONFIG_PARSE_HELP; } else { found = 0; prop = __ecore_config_bundle_local->data; while (prop) { if (short_opt == prop->short_opt) { found = 1; if ((ret = ecore_config_parse_set(prop, argv[++nextarg], NULL, short_opt)) != ECORE_CONFIG_PARSE_CONTINUE) return ret; break; } prop = prop->next; } if (!found) { callback = _ecore_config_arg_callbacks; while (callback) { if (short_opt == callback->short_opt) { found = 1; if (callback->type == ECORE_CONFIG_NIL) { callback->func(NULL, callback->data); } else { if (!argv[++nextarg]) { ERR("Missing expected argument for option -%c", short_opt); return ECORE_CONFIG_PARSE_EXIT; } callback->func(argv[nextarg], callback->data); } break; } callback = callback->next; } } if (!found) { ERR("Unrecognised option '%c'", short_opt); ERR("Try using -h or --help for more information.\n"); return ECORE_CONFIG_PARSE_EXIT; } } short_opt = *(arg + ++next_short_opt); } } nextarg++; } return ECORE_CONFIG_PARSE_CONTINUE; } /** * Sets the description string used by @ref ecore_config_args_display . * @param description Description of application. */ void ecore_config_app_describe(char *description) { if (__ecore_config_app_description) free(__ecore_config_app_description); __ecore_config_app_description = strdup(description); }