parse app Categories better. parse a list of strings into a gchar**

This commit is contained in:
Dana Jansens 2010-06-03 13:53:19 -04:00
parent 78a8f407a9
commit b025a0268f
4 changed files with 97 additions and 43 deletions

View file

@ -85,7 +85,7 @@ static void parse_value_free(ObtDDParseValue *v)
g_free(v->value.string); break; g_free(v->value.string); break;
case OBT_DDPARSE_STRINGS: case OBT_DDPARSE_STRINGS:
case OBT_DDPARSE_LOCALESTRINGS: case OBT_DDPARSE_LOCALESTRINGS:
g_free(v->value.strings.s); g_strfreev(v->value.strings.a);
v->value.strings.n = 0; v->value.strings.n = 0;
break; break;
case OBT_DDPARSE_BOOLEAN: 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 /*! Reads an input string, strips out invalid stuff, and parses
backslash-stuff. 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, static gchar* parse_value_string(const gchar *in,
gboolean locale, gboolean locale,
gulong *nstrings, gboolean semicolonterminate,
gulong *len,
const ObtDDParse *const parse, const ObtDDParse *const parse,
gboolean *error) gboolean *error)
{ {
const gint bytes = strlen(in); gint bytes;
gboolean backslash; gboolean backslash;
gchar *out, *o; gchar *out, *o;
const gchar *end, *i; const gchar *end, *i;
g_return_val_if_fail(in != NULL, NULL); /* find the end/size of the string */
backslash = FALSE;
if (!locale) { for (end = in; *end; ++end) {
end = in + bytes; if (semicolonterminate) {
for (i = in; i < end; ++i) { if (backslash) backslash = FALSE;
if ((guchar)*i >= 127 || (guchar)*i < 32) { else if (*end == '\\') backslash = TRUE;
/* non-control character ascii */ else if (*end == ';') break;
end = i;
parse_error("Invalid bytes in string", parse, error);
break;
}
} }
} }
else if (!g_utf8_validate(in, bytes, &end)) bytes = end - in;
parse_error("Invalid bytes in localestring", parse, error);
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); out = g_new(char, bytes + 1);
if (len) *len = 0;
i = in; o = out; i = in; o = out;
backslash = FALSE; backslash = FALSE;
while (i < end) { while (i < end) {
@ -181,18 +180,16 @@ static gchar* parse_value_string(const gchar *in,
} }
else if (*i == '\\') else if (*i == '\\')
backslash = TRUE; backslash = TRUE;
else if (*i == ';' && nstrings) { else if ((guchar)*i >= 127 || (guchar)*i < 32) {
++nstrings;
*o = '\0';
}
else if ((guchar)*i == 127 || (guchar)*i < 32) {
/* avoid ascii control characters */ /* avoid ascii control characters */
parse_error("Found control character in string", parse, error); parse_error("Found control character in string", parse, error);
break; break;
} }
else { else {
memcpy(o, i, next-i); const gulong s = next-i;
o += next-i; memcpy(o, i, s);
o += s;
if (len) *len += s;
} }
i = next; i = next;
} }
@ -200,6 +197,44 @@ static gchar* parse_value_string(const gchar *in,
return out; 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, static guint parse_value_environments(const gchar *in,
const ObtDDParse *const parse, const ObtDDParse *const parse,
gboolean *error) gboolean *error)
@ -606,13 +641,13 @@ static gboolean parse_desktop_entry_value(gchar *key, const gchar *val,
gboolean percent; gboolean percent;
gboolean found; 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); g_assert(v.value.string);
/* an exec string can only contain one of the file/url-opening %'s */ /* an exec string can only contain one of the file/url-opening %'s */
percent = found = FALSE; percent = found = FALSE;
for (c = v.value.string; *c; ++c) { for (c = v.value.string; *c; ++c) {
if (*c == '%') percent = !percent;
if (percent) { if (percent) {
switch (*c) { switch (*c) {
case 'f': case 'f':
@ -641,6 +676,7 @@ static gboolean parse_desktop_entry_value(gchar *key, const gchar *val,
case 'i': case 'i':
case 'c': case 'c':
case 'k': case 'k':
case '%':
break; break;
default: default:
m = g_strdup_printf("Malformed Exec key, " 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 */ parse_error(m, parse, NULL); /* just a warning */
g_free(m); g_free(m);
} }
percent = FALSE;
} }
else if (*c == '%') percent = TRUE;
} }
break; break;
} }
case OBT_DDPARSE_STRING: 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); g_assert(v.value.string);
break; break;
case OBT_DDPARSE_LOCALESTRING: 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); g_assert(v.value.string);
break; break;
case OBT_DDPARSE_STRINGS: case OBT_DDPARSE_STRINGS:
v.value.strings.s = parse_value_string(val, FALSE, &v.value.strings.n, v.value.strings.a = parse_value_strings(val, FALSE, &v.value.strings.n,
parse, error); parse, error);
g_assert(v.value.strings.s); g_assert(v.value.strings.a);
g_assert(v.value.strings.n); g_assert(v.value.strings.n);
break; break;
case OBT_DDPARSE_LOCALESTRINGS: case OBT_DDPARSE_LOCALESTRINGS:
v.value.strings.s = parse_value_string(val, TRUE, &v.value.strings.n, v.value.strings.a = parse_value_strings(val, TRUE, &v.value.strings.n,
parse, error); parse, error);
g_assert(v.value.strings.s); g_assert(v.value.strings.a);
g_assert(v.value.strings.n); g_assert(v.value.strings.n);
break; break;
case OBT_DDPARSE_BOOLEAN: case OBT_DDPARSE_BOOLEAN:

View file

@ -38,7 +38,7 @@ typedef struct _ObtDDParseValue {
union _ObtDDParseValueValue { union _ObtDDParseValueValue {
gchar *string; gchar *string;
struct _ObtDDParseValueStrings { struct _ObtDDParseValueStrings {
gchar *s; gchar **a;
gulong n; gulong n;
} strings; } strings;
gboolean boolean; gboolean boolean;

View file

@ -51,6 +51,7 @@ struct _ObtLink {
GQuark *categories; /*!< Array of quarks representing the GQuark *categories; /*!< Array of quarks representing the
application's categories */ application's categories */
gulong n_categories; /*!< Number of categories for the app */
ObtLinkAppStartup startup; ObtLinkAppStartup startup;
gchar *startup_wmclass; 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 */ /* parse link->d.app.exec to determine link->d.app.open */
percent = FALSE; percent = FALSE;
for (c = link->d.app.exec; *c; ++c) { for (c = link->d.app.exec; *c; ++c) {
if (*c == '%') percent = !percent;
if (percent) { if (percent) {
switch (*c) { switch (*c) {
case 'f': link->d.app.open = OBT_LINK_APP_SINGLE_LOCAL; break; 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 '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_SINGLE_URL; break;
case 'U': link->d.app.open = OBT_LINK_APP_MULTI_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"))) { if ((v = g_hash_table_lookup(keys, "TryExec"))) {
@ -172,11 +175,11 @@ ObtLink* obt_link_from_ddfile(const gchar *ddname, GSList *paths,
gchar *end; gchar *end;
link->d.app.categories = g_new(GQuark, v->value.strings.n); 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) { for (i = 0; i < v->value.strings.n; ++i) {
while (*end) ++end; link->d.app.categories[i] =
link->d.app.categories[i] = g_quark_from_string(c); g_quark_from_string(v->value.strings.a[i]);
c = end = end+1; /* next */ c = end = end+1; /* next */
} }
} }
@ -219,3 +222,13 @@ void obt_link_unref(ObtLink *dd)
g_slice_free(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;
}

View file

@ -100,7 +100,8 @@ const gchar* obt_link_app_executable (ObtLink *e);
/*! Returns the path in which the application should be run */ /*! Returns the path in which the application should be run */
const gchar* obt_link_app_path (ObtLink *e); const gchar* obt_link_app_path (ObtLink *e);
gboolean obt_link_app_run_in_terminal (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, /*! Returns a combination of values in the ObtLinkAppOpen enum,
specifying if the application can be launched to open one or more files specifying if the application can be launched to open one or more files
and URLs. */ and URLs. */