diff --git a/obt/ddparse.c b/obt/ddparse.c index aaecda01..149134d8 100644 --- a/obt/ddparse.c +++ b/obt/ddparse.c @@ -85,7 +85,7 @@ static void parse_value_free(ObtDDParseValue *v) g_free(v->value.string); break; case OBT_DDPARSE_STRINGS: case OBT_DDPARSE_LOCALESTRINGS: - g_free(v->value.strings.s); + g_strfreev(v->value.strings.a); v->value.strings.n = 0; break; case OBT_DDPARSE_BOOLEAN: @@ -120,40 +120,39 @@ static void parse_group_free(ObtDDParseGroup *g) /*! Reads an input string, strips out invalid stuff, and parses backslash-stuff. - If @nstrings is not NULL, then it splits the output string at ';' - characters. They are all returned in the same string with null zeros - between them, @nstrings is set to the number of such strings. */ static gchar* parse_value_string(const gchar *in, gboolean locale, - gulong *nstrings, + gboolean semicolonterminate, + gulong *len, const ObtDDParse *const parse, gboolean *error) { - const gint bytes = strlen(in); + gint bytes; gboolean backslash; gchar *out, *o; const gchar *end, *i; - g_return_val_if_fail(in != NULL, NULL); - - if (!locale) { - end = in + bytes; - for (i = in; i < end; ++i) { - if ((guchar)*i >= 127 || (guchar)*i < 32) { - /* non-control character ascii */ - end = i; - parse_error("Invalid bytes in string", parse, error); - break; - } + /* find the end/size of the string */ + backslash = FALSE; + for (end = in; *end; ++end) { + if (semicolonterminate) { + if (backslash) backslash = FALSE; + else if (*end == '\\') backslash = TRUE; + else if (*end == ';') break; } } - else if (!g_utf8_validate(in, bytes, &end)) - parse_error("Invalid bytes in localestring", parse, error); + bytes = end - in; - if (nstrings) *nstrings = 1; + g_return_val_if_fail(in != NULL, NULL); + + if (locale && !g_utf8_validate(in, bytes, &end)) { + parse_error("Invalid bytes in localestring", parse, error); + bytes = end - in; + } out = g_new(char, bytes + 1); + if (len) *len = 0; i = in; o = out; backslash = FALSE; while (i < end) { @@ -181,18 +180,16 @@ static gchar* parse_value_string(const gchar *in, } else if (*i == '\\') backslash = TRUE; - else if (*i == ';' && nstrings) { - ++nstrings; - *o = '\0'; - } - else if ((guchar)*i == 127 || (guchar)*i < 32) { + else if ((guchar)*i >= 127 || (guchar)*i < 32) { /* avoid ascii control characters */ parse_error("Found control character in string", parse, error); break; } else { - memcpy(o, i, next-i); - o += next-i; + const gulong s = next-i; + memcpy(o, i, s); + o += s; + if (len) *len += s; } i = next; } @@ -200,6 +197,44 @@ static gchar* parse_value_string(const gchar *in, return out; } + +/*! Reads a list of input strings, strips out invalid stuff, and parses + backslash-stuff. + */ +static gchar** parse_value_strings(const gchar *in, + gboolean locale, + gulong *nstrings, + const ObtDDParse *const parse, + gboolean *error) +{ + gchar **out; + const gchar *i; + + out = g_new(gchar*, 1); + out[0] = NULL; + *nstrings = 0; + + i = in; + while (TRUE) { + gchar *a; + gulong len; + + a = parse_value_string(i, locale, TRUE, &len, parse, error); + i += len; + + if (len) { + (*nstrings)++; + out = g_renew(gchar*, out, *nstrings+1); + out[*nstrings-1] = a; + out[*nstrings] = NULL; + } + + if (!*i) break; /* no more strings */ + ++i; + } + return out; +} + static guint parse_value_environments(const gchar *in, const ObtDDParse *const parse, gboolean *error) @@ -606,13 +641,13 @@ static gboolean parse_desktop_entry_value(gchar *key, const gchar *val, gboolean percent; gboolean found; - v.value.string = parse_value_string(val, FALSE, NULL, parse, error); + v.value.string = parse_value_string(val, FALSE, FALSE, NULL, + parse, error); g_assert(v.value.string); /* an exec string can only contain one of the file/url-opening %'s */ percent = found = FALSE; for (c = v.value.string; *c; ++c) { - if (*c == '%') percent = !percent; if (percent) { switch (*c) { case 'f': @@ -641,6 +676,7 @@ static gboolean parse_desktop_entry_value(gchar *key, const gchar *val, case 'i': case 'c': case 'k': + case '%': break; default: m = g_strdup_printf("Malformed Exec key, " @@ -648,28 +684,32 @@ static gboolean parse_desktop_entry_value(gchar *key, const gchar *val, parse_error(m, parse, NULL); /* just a warning */ g_free(m); } + percent = FALSE; } + else if (*c == '%') percent = TRUE; } break; } case OBT_DDPARSE_STRING: - v.value.string = parse_value_string(val, FALSE, NULL, parse, error); + v.value.string = parse_value_string(val, FALSE, FALSE, NULL, + parse, error); g_assert(v.value.string); break; case OBT_DDPARSE_LOCALESTRING: - v.value.string = parse_value_string(val, TRUE, NULL, parse, error); + v.value.string = parse_value_string(val, TRUE, FALSE, NULL, + parse, error); g_assert(v.value.string); break; case OBT_DDPARSE_STRINGS: - v.value.strings.s = parse_value_string(val, FALSE, &v.value.strings.n, - parse, error); - g_assert(v.value.strings.s); + v.value.strings.a = parse_value_strings(val, FALSE, &v.value.strings.n, + parse, error); + g_assert(v.value.strings.a); g_assert(v.value.strings.n); break; case OBT_DDPARSE_LOCALESTRINGS: - v.value.strings.s = parse_value_string(val, TRUE, &v.value.strings.n, - parse, error); - g_assert(v.value.strings.s); + v.value.strings.a = parse_value_strings(val, TRUE, &v.value.strings.n, + parse, error); + g_assert(v.value.strings.a); g_assert(v.value.strings.n); break; case OBT_DDPARSE_BOOLEAN: diff --git a/obt/ddparse.h b/obt/ddparse.h index 96e254c1..d261f5bb 100644 --- a/obt/ddparse.h +++ b/obt/ddparse.h @@ -38,7 +38,7 @@ typedef struct _ObtDDParseValue { union _ObtDDParseValueValue { gchar *string; struct _ObtDDParseValueStrings { - gchar *s; + gchar **a; gulong n; } strings; gboolean boolean; diff --git a/obt/link.c b/obt/link.c index a1d08270..b9073de4 100644 --- a/obt/link.c +++ b/obt/link.c @@ -51,6 +51,7 @@ struct _ObtLink { GQuark *categories; /*!< Array of quarks representing the application's categories */ + gulong n_categories; /*!< Number of categories for the app */ ObtLinkAppStartup startup; gchar *startup_wmclass; @@ -128,15 +129,17 @@ ObtLink* obt_link_from_ddfile(const gchar *ddname, GSList *paths, /* parse link->d.app.exec to determine link->d.app.open */ percent = FALSE; for (c = link->d.app.exec; *c; ++c) { - if (*c == '%') percent = !percent; if (percent) { switch (*c) { case 'f': link->d.app.open = OBT_LINK_APP_SINGLE_LOCAL; break; case 'F': link->d.app.open = OBT_LINK_APP_MULTI_LOCAL; break; case 'u': link->d.app.open = OBT_LINK_APP_SINGLE_URL; break; case 'U': link->d.app.open = OBT_LINK_APP_MULTI_URL; break; + default: percent = FALSE; } + if (percent) break; /* found f/F/u/U */ } + else if (*c == '%') percent = TRUE; } if ((v = g_hash_table_lookup(keys, "TryExec"))) { @@ -172,11 +175,11 @@ ObtLink* obt_link_from_ddfile(const gchar *ddname, GSList *paths, gchar *end; link->d.app.categories = g_new(GQuark, v->value.strings.n); + link->d.app.n_categories = v->value.strings.n; - c = end = v->value.strings.s; for (i = 0; i < v->value.strings.n; ++i) { - while (*end) ++end; - link->d.app.categories[i] = g_quark_from_string(c); + link->d.app.categories[i] = + g_quark_from_string(v->value.strings.a[i]); c = end = end+1; /* next */ } } @@ -219,3 +222,13 @@ void obt_link_unref(ObtLink *dd) g_slice_free(ObtLink, dd); } } + +const GQuark* obt_link_app_categories(ObtLink *e, gulong *n) +{ + g_return_val_if_fail(e != NULL, NULL); + g_return_val_if_fail(e->type == OBT_LINK_TYPE_APPLICATION, NULL); + g_return_val_if_fail(n != NULL, NULL); + + *n = e->d.app.n_categories; + return e->d.app.categories; +} diff --git a/obt/link.h b/obt/link.h index 4c1fb8aa..9ad86cc9 100644 --- a/obt/link.h +++ b/obt/link.h @@ -100,7 +100,8 @@ const gchar* obt_link_app_executable (ObtLink *e); /*! Returns the path in which the application should be run */ const gchar* obt_link_app_path (ObtLink *e); gboolean obt_link_app_run_in_terminal (ObtLink *e); -const gchar** obt_link_app_mime_types (ObtLink *e); +const gchar*const* obt_link_app_mime_types (ObtLink *e); +const GQuark* obt_link_app_categories (ObtLink *e, gulong *n); /*! Returns a combination of values in the ObtLinkAppOpen enum, specifying if the application can be launched to open one or more files and URLs. */