Changed indentation everywhere
This commit is contained in:
@@ -30,280 +30,280 @@
|
||||
|
||||
static gint compare_strings(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
return strnatcasecmp((const char *)a, (const char *)b);
|
||||
return strnatcasecmp((const char *)a, (const char *)b);
|
||||
}
|
||||
|
||||
int parse_dektop_line(char *line, char **key, char **value)
|
||||
{
|
||||
char *p;
|
||||
int found = 0;
|
||||
*key = line;
|
||||
for (p = line; *p; p++) {
|
||||
if (*p == '=') {
|
||||
*value = p + 1;
|
||||
*p = 0;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
return 0;
|
||||
if (found && (strlen(*key) == 0 || strlen(*value) == 0))
|
||||
return 0;
|
||||
return 1;
|
||||
char *p;
|
||||
int found = 0;
|
||||
*key = line;
|
||||
for (p = line; *p; p++) {
|
||||
if (*p == '=') {
|
||||
*value = p + 1;
|
||||
*p = 0;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
return 0;
|
||||
if (found && (strlen(*key) == 0 || strlen(*value) == 0))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void expand_exec(DesktopEntry *entry, const char *path)
|
||||
{
|
||||
// Expand % in exec
|
||||
// %i -> --icon Icon
|
||||
// %c -> Name
|
||||
// %k -> path
|
||||
if (entry->exec) {
|
||||
char *exec2 = calloc(strlen(entry->exec) + (entry->name ? strlen(entry->name) : 1) +
|
||||
(entry->icon ? strlen(entry->icon) : 1) + 100,
|
||||
1);
|
||||
char *p, *q;
|
||||
// p will never point to an escaped char
|
||||
for (p = entry->exec, q = exec2; *p; p++, q++) {
|
||||
*q = *p; // Copy
|
||||
if (*p == '\\') {
|
||||
p++, q++;
|
||||
// Copy the escaped char
|
||||
if (*p == '%') // For % we delete the backslash, i.e. write % over it
|
||||
q--;
|
||||
*q = *p;
|
||||
if (!*p)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (*p == '%') {
|
||||
p++;
|
||||
if (!*p)
|
||||
break;
|
||||
if (*p == 'i' && entry->icon != NULL) {
|
||||
sprintf(q, "--icon '%s'", entry->icon);
|
||||
q += strlen("--icon ''");
|
||||
q += strlen(entry->icon);
|
||||
q--; // To balance the q++ in the for
|
||||
} else if (*p == 'c' && entry->name != NULL) {
|
||||
sprintf(q, "'%s'", entry->name);
|
||||
q += strlen("''");
|
||||
q += strlen(entry->name);
|
||||
q--; // To balance the q++ in the for
|
||||
} else if (*p == 'c') {
|
||||
sprintf(q, "'%s'", path);
|
||||
q += strlen("''");
|
||||
q += strlen(path);
|
||||
q--; // To balance the q++ in the for
|
||||
} else {
|
||||
// We don't care about other expansions
|
||||
q--; // Delete the last % from q
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*q = '\0';
|
||||
free(entry->exec);
|
||||
entry->exec = exec2;
|
||||
}
|
||||
// Expand % in exec
|
||||
// %i -> --icon Icon
|
||||
// %c -> Name
|
||||
// %k -> path
|
||||
if (entry->exec) {
|
||||
char *exec2 = calloc(strlen(entry->exec) + (entry->name ? strlen(entry->name) : 1) +
|
||||
(entry->icon ? strlen(entry->icon) : 1) + 100,
|
||||
1);
|
||||
char *p, *q;
|
||||
// p will never point to an escaped char
|
||||
for (p = entry->exec, q = exec2; *p; p++, q++) {
|
||||
*q = *p; // Copy
|
||||
if (*p == '\\') {
|
||||
p++, q++;
|
||||
// Copy the escaped char
|
||||
if (*p == '%') // For % we delete the backslash, i.e. write % over it
|
||||
q--;
|
||||
*q = *p;
|
||||
if (!*p)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (*p == '%') {
|
||||
p++;
|
||||
if (!*p)
|
||||
break;
|
||||
if (*p == 'i' && entry->icon != NULL) {
|
||||
sprintf(q, "--icon '%s'", entry->icon);
|
||||
q += strlen("--icon ''");
|
||||
q += strlen(entry->icon);
|
||||
q--; // To balance the q++ in the for
|
||||
} else if (*p == 'c' && entry->name != NULL) {
|
||||
sprintf(q, "'%s'", entry->name);
|
||||
q += strlen("''");
|
||||
q += strlen(entry->name);
|
||||
q--; // To balance the q++ in the for
|
||||
} else if (*p == 'c') {
|
||||
sprintf(q, "'%s'", path);
|
||||
q += strlen("''");
|
||||
q += strlen(path);
|
||||
q--; // To balance the q++ in the for
|
||||
} else {
|
||||
// We don't care about other expansions
|
||||
q--; // Delete the last % from q
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*q = '\0';
|
||||
free(entry->exec);
|
||||
entry->exec = exec2;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean read_desktop_file_full_path(const char *path, DesktopEntry *entry)
|
||||
{
|
||||
entry->name = entry->generic_name = entry->icon = entry->exec = entry->cwd = NULL;
|
||||
entry->hidden_from_menus = FALSE;
|
||||
entry->name = entry->generic_name = entry->icon = entry->exec = entry->cwd = NULL;
|
||||
entry->hidden_from_menus = FALSE;
|
||||
|
||||
FILE *fp = fopen(path, "rt");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "Could not open file %s\n", path);
|
||||
return FALSE;
|
||||
}
|
||||
FILE *fp = fopen(path, "rt");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "Could not open file %s\n", path);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const gchar **languages = (const gchar **)g_get_language_names();
|
||||
// lang_index is the index of the language for the best Name key in the language vector
|
||||
// lang_index_default is a constant that encodes the Name key without a language
|
||||
int lang_index_default = 1;
|
||||
const gchar **languages = (const gchar **)g_get_language_names();
|
||||
// lang_index is the index of the language for the best Name key in the language vector
|
||||
// lang_index_default is a constant that encodes the Name key without a language
|
||||
int lang_index_default = 1;
|
||||
#define LANG_DBG 0
|
||||
if (LANG_DBG)
|
||||
printf("Languages:");
|
||||
for (int i = 0; languages[i]; i++) {
|
||||
lang_index_default = i + 1;
|
||||
if (LANG_DBG)
|
||||
printf(" %s", languages[i]);
|
||||
}
|
||||
if (LANG_DBG)
|
||||
printf("\n");
|
||||
// we currently do not know about any Name key at all, so use an invalid index
|
||||
int lang_index_name = lang_index_default + 1;
|
||||
int lang_index_generic_name = lang_index_default + 1;
|
||||
if (LANG_DBG)
|
||||
printf("Languages:");
|
||||
for (int i = 0; languages[i]; i++) {
|
||||
lang_index_default = i + 1;
|
||||
if (LANG_DBG)
|
||||
printf(" %s", languages[i]);
|
||||
}
|
||||
if (LANG_DBG)
|
||||
printf("\n");
|
||||
// we currently do not know about any Name key at all, so use an invalid index
|
||||
int lang_index_name = lang_index_default + 1;
|
||||
int lang_index_generic_name = lang_index_default + 1;
|
||||
|
||||
gboolean inside_desktop_entry = 0;
|
||||
char *line = NULL;
|
||||
size_t line_size;
|
||||
while (getline(&line, &line_size, fp) >= 0) {
|
||||
int len = strlen(line);
|
||||
if (len == 0)
|
||||
continue;
|
||||
if (line[len - 1] == '\n')
|
||||
line[len - 1] = '\0';
|
||||
if (line[0] == '[') {
|
||||
inside_desktop_entry = (strcmp(line, "[Desktop Entry]") == 0);
|
||||
}
|
||||
char *key, *value;
|
||||
if (inside_desktop_entry && parse_dektop_line(line, &key, &value)) {
|
||||
if (strstr(key, "Name") == key) {
|
||||
if (strcmp(key, "Name") == 0 && lang_index_name > lang_index_default) {
|
||||
entry->name = strdup(value);
|
||||
lang_index_name = lang_index_default;
|
||||
} else {
|
||||
for (int i = 0; languages[i] && i < lang_index_name; i++) {
|
||||
gchar *localized_key = g_strdup_printf("Name[%s]", languages[i]);
|
||||
if (strcmp(key, localized_key) == 0) {
|
||||
if (entry->name)
|
||||
free(entry->name);
|
||||
entry->name = strdup(value);
|
||||
lang_index_name = i;
|
||||
}
|
||||
g_free(localized_key);
|
||||
}
|
||||
}
|
||||
} else if (strstr(key, "GenericName") == key) {
|
||||
if (strcmp(key, "GenericName") == 0 && lang_index_generic_name > lang_index_default) {
|
||||
entry->generic_name = strdup(value);
|
||||
lang_index_generic_name = lang_index_default;
|
||||
} else {
|
||||
for (int i = 0; languages[i] && i < lang_index_generic_name; i++) {
|
||||
gchar *localized_key = g_strdup_printf("GenericName[%s]", languages[i]);
|
||||
if (strcmp(key, localized_key) == 0) {
|
||||
if (entry->generic_name)
|
||||
free(entry->generic_name);
|
||||
entry->generic_name = strdup(value);
|
||||
lang_index_generic_name = i;
|
||||
}
|
||||
g_free(localized_key);
|
||||
}
|
||||
}
|
||||
} else if (!entry->exec && strcmp(key, "Exec") == 0) {
|
||||
entry->exec = strdup(value);
|
||||
} else if (!entry->cwd && strcmp(key, "Path") == 0) {
|
||||
entry->cwd = strdup(value);
|
||||
} else if (!entry->icon && strcmp(key, "Icon") == 0) {
|
||||
entry->icon = strdup(value);
|
||||
} else if (strcmp(key, "NoDisplay") == 0) {
|
||||
entry->hidden_from_menus = strcasecmp(value, "true") == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
// From this point:
|
||||
// entry->name, entry->generic_name, entry->icon, entry->exec will never be empty strings (can be NULL though)
|
||||
gboolean inside_desktop_entry = 0;
|
||||
char *line = NULL;
|
||||
size_t line_size;
|
||||
while (getline(&line, &line_size, fp) >= 0) {
|
||||
int len = strlen(line);
|
||||
if (len == 0)
|
||||
continue;
|
||||
if (line[len - 1] == '\n')
|
||||
line[len - 1] = '\0';
|
||||
if (line[0] == '[') {
|
||||
inside_desktop_entry = (strcmp(line, "[Desktop Entry]") == 0);
|
||||
}
|
||||
char *key, *value;
|
||||
if (inside_desktop_entry && parse_dektop_line(line, &key, &value)) {
|
||||
if (strstr(key, "Name") == key) {
|
||||
if (strcmp(key, "Name") == 0 && lang_index_name > lang_index_default) {
|
||||
entry->name = strdup(value);
|
||||
lang_index_name = lang_index_default;
|
||||
} else {
|
||||
for (int i = 0; languages[i] && i < lang_index_name; i++) {
|
||||
gchar *localized_key = g_strdup_printf("Name[%s]", languages[i]);
|
||||
if (strcmp(key, localized_key) == 0) {
|
||||
if (entry->name)
|
||||
free(entry->name);
|
||||
entry->name = strdup(value);
|
||||
lang_index_name = i;
|
||||
}
|
||||
g_free(localized_key);
|
||||
}
|
||||
}
|
||||
} else if (strstr(key, "GenericName") == key) {
|
||||
if (strcmp(key, "GenericName") == 0 && lang_index_generic_name > lang_index_default) {
|
||||
entry->generic_name = strdup(value);
|
||||
lang_index_generic_name = lang_index_default;
|
||||
} else {
|
||||
for (int i = 0; languages[i] && i < lang_index_generic_name; i++) {
|
||||
gchar *localized_key = g_strdup_printf("GenericName[%s]", languages[i]);
|
||||
if (strcmp(key, localized_key) == 0) {
|
||||
if (entry->generic_name)
|
||||
free(entry->generic_name);
|
||||
entry->generic_name = strdup(value);
|
||||
lang_index_generic_name = i;
|
||||
}
|
||||
g_free(localized_key);
|
||||
}
|
||||
}
|
||||
} else if (!entry->exec && strcmp(key, "Exec") == 0) {
|
||||
entry->exec = strdup(value);
|
||||
} else if (!entry->cwd && strcmp(key, "Path") == 0) {
|
||||
entry->cwd = strdup(value);
|
||||
} else if (!entry->icon && strcmp(key, "Icon") == 0) {
|
||||
entry->icon = strdup(value);
|
||||
} else if (strcmp(key, "NoDisplay") == 0) {
|
||||
entry->hidden_from_menus = strcasecmp(value, "true") == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
// From this point:
|
||||
// entry->name, entry->generic_name, entry->icon, entry->exec will never be empty strings (can be NULL though)
|
||||
|
||||
expand_exec(entry, entry->path);
|
||||
expand_exec(entry, entry->path);
|
||||
|
||||
free(line);
|
||||
return entry->exec != NULL;
|
||||
free(line);
|
||||
return entry->exec != NULL;
|
||||
}
|
||||
|
||||
gboolean read_desktop_file_from_dir(const char *path, const char *file_name, DesktopEntry *entry)
|
||||
{
|
||||
gchar *full_path = g_build_filename(path, file_name, NULL);
|
||||
if (read_desktop_file_full_path(full_path, entry)) {
|
||||
g_free(full_path);
|
||||
return TRUE;
|
||||
}
|
||||
free_and_null(entry->name);
|
||||
free_and_null(entry->generic_name);
|
||||
free_and_null(entry->icon);
|
||||
free_and_null(entry->exec);
|
||||
free_and_null(entry->cwd);
|
||||
gchar *full_path = g_build_filename(path, file_name, NULL);
|
||||
if (read_desktop_file_full_path(full_path, entry)) {
|
||||
g_free(full_path);
|
||||
return TRUE;
|
||||
}
|
||||
free_and_null(entry->name);
|
||||
free_and_null(entry->generic_name);
|
||||
free_and_null(entry->icon);
|
||||
free_and_null(entry->exec);
|
||||
free_and_null(entry->cwd);
|
||||
|
||||
GList *subdirs = NULL;
|
||||
GList *subdirs = NULL;
|
||||
|
||||
GDir *d = g_dir_open(path, 0, NULL);
|
||||
if (d) {
|
||||
const gchar *name;
|
||||
while ((name = g_dir_read_name(d))) {
|
||||
gchar *child = g_build_filename(path, name, NULL);
|
||||
if (g_file_test(child, G_FILE_TEST_IS_DIR)) {
|
||||
subdirs = g_list_append(subdirs, child);
|
||||
} else {
|
||||
g_free(child);
|
||||
}
|
||||
}
|
||||
g_dir_close(d);
|
||||
}
|
||||
GDir *d = g_dir_open(path, 0, NULL);
|
||||
if (d) {
|
||||
const gchar *name;
|
||||
while ((name = g_dir_read_name(d))) {
|
||||
gchar *child = g_build_filename(path, name, NULL);
|
||||
if (g_file_test(child, G_FILE_TEST_IS_DIR)) {
|
||||
subdirs = g_list_append(subdirs, child);
|
||||
} else {
|
||||
g_free(child);
|
||||
}
|
||||
}
|
||||
g_dir_close(d);
|
||||
}
|
||||
|
||||
subdirs = g_list_sort(subdirs, compare_strings);
|
||||
gboolean found = FALSE;
|
||||
for (GList *l = subdirs; l; l = g_list_next(l)) {
|
||||
if (read_desktop_file_from_dir(l->data, file_name, entry)) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
subdirs = g_list_sort(subdirs, compare_strings);
|
||||
gboolean found = FALSE;
|
||||
for (GList *l = subdirs; l; l = g_list_next(l)) {
|
||||
if (read_desktop_file_from_dir(l->data, file_name, entry)) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (GList *l = subdirs; l; l = g_list_next(l)) {
|
||||
g_free(l->data);
|
||||
}
|
||||
g_list_free(subdirs);
|
||||
g_free(full_path);
|
||||
for (GList *l = subdirs; l; l = g_list_next(l)) {
|
||||
g_free(l->data);
|
||||
}
|
||||
g_list_free(subdirs);
|
||||
g_free(full_path);
|
||||
|
||||
return found;
|
||||
return found;
|
||||
}
|
||||
|
||||
gboolean read_desktop_file(const char *path, DesktopEntry *entry)
|
||||
{
|
||||
entry->path = strdup(path);
|
||||
entry->name = entry->generic_name = entry->icon = entry->exec = entry->cwd = NULL;
|
||||
entry->path = strdup(path);
|
||||
entry->name = entry->generic_name = entry->icon = entry->exec = entry->cwd = NULL;
|
||||
|
||||
if (strchr(path, '/'))
|
||||
return read_desktop_file_full_path(path, entry);
|
||||
for (const GSList *location = get_apps_locations(); location; location = g_slist_next(location)) {
|
||||
if (read_desktop_file_from_dir(location->data, path, entry))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
if (strchr(path, '/'))
|
||||
return read_desktop_file_full_path(path, entry);
|
||||
for (const GSList *location = get_apps_locations(); location; location = g_slist_next(location)) {
|
||||
if (read_desktop_file_from_dir(location->data, path, entry))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void free_desktop_entry(DesktopEntry *entry)
|
||||
{
|
||||
free_and_null(entry->name);
|
||||
free_and_null(entry->generic_name);
|
||||
free_and_null(entry->icon);
|
||||
free_and_null(entry->exec);
|
||||
free_and_null(entry->path);
|
||||
free_and_null(entry->cwd);
|
||||
free_and_null(entry->name);
|
||||
free_and_null(entry->generic_name);
|
||||
free_and_null(entry->icon);
|
||||
free_and_null(entry->exec);
|
||||
free_and_null(entry->path);
|
||||
free_and_null(entry->cwd);
|
||||
}
|
||||
|
||||
void test_read_desktop_file()
|
||||
{
|
||||
fprintf(stdout, "\033[1;33m");
|
||||
DesktopEntry entry;
|
||||
read_desktop_file("/usr/share/applications/firefox.desktop", &entry);
|
||||
printf("Name:%s GenericName:%s Icon:%s Exec:%s\n", entry.name, entry.generic_name, entry.icon, entry.exec);
|
||||
fprintf(stdout, "\033[0m");
|
||||
fprintf(stdout, "\033[1;33m");
|
||||
DesktopEntry entry;
|
||||
read_desktop_file("/usr/share/applications/firefox.desktop", &entry);
|
||||
printf("Name:%s GenericName:%s Icon:%s Exec:%s\n", entry.name, entry.generic_name, entry.icon, entry.exec);
|
||||
fprintf(stdout, "\033[0m");
|
||||
}
|
||||
|
||||
GSList *apps_locations = NULL;
|
||||
// Do not free the result.
|
||||
const GSList *get_apps_locations()
|
||||
{
|
||||
if (apps_locations)
|
||||
return apps_locations;
|
||||
if (apps_locations)
|
||||
return apps_locations;
|
||||
|
||||
apps_locations = load_locations_from_env(apps_locations, "XDG_DATA_HOME", "applications", NULL);
|
||||
apps_locations = load_locations_from_env(apps_locations, "XDG_DATA_HOME", "applications", NULL);
|
||||
|
||||
apps_locations =
|
||||
g_slist_append(apps_locations, g_build_filename(g_get_home_dir(), ".local/share/applications", NULL));
|
||||
apps_locations =
|
||||
g_slist_append(apps_locations, g_build_filename(g_get_home_dir(), ".local/share/applications", NULL));
|
||||
|
||||
apps_locations = load_locations_from_env(apps_locations, "XDG_DATA_DIRS", "applications", NULL);
|
||||
apps_locations = load_locations_from_env(apps_locations, "XDG_DATA_DIRS", "applications", NULL);
|
||||
|
||||
apps_locations = g_slist_append(apps_locations, g_strdup("/usr/local/share/applications"));
|
||||
apps_locations = g_slist_append(apps_locations, g_strdup("/usr/share/applications"));
|
||||
apps_locations = g_slist_append(apps_locations, g_strdup("/opt/share/applications"));
|
||||
apps_locations = g_slist_append(apps_locations, g_strdup("/usr/local/share/applications"));
|
||||
apps_locations = g_slist_append(apps_locations, g_strdup("/usr/share/applications"));
|
||||
apps_locations = g_slist_append(apps_locations, g_strdup("/opt/share/applications"));
|
||||
|
||||
apps_locations = slist_remove_duplicates(apps_locations, g_str_equal, g_free);
|
||||
apps_locations = slist_remove_duplicates(apps_locations, g_str_equal, g_free);
|
||||
|
||||
return apps_locations;
|
||||
return apps_locations;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user