parse app Categories better. parse a list of strings into a gchar**
This commit is contained in:
parent
78a8f407a9
commit
b025a0268f
4 changed files with 97 additions and 43 deletions
114
obt/ddparse.c
114
obt/ddparse.c
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
21
obt/link.c
21
obt/link.c
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
Loading…
Reference in a new issue