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:
/*! 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) {
}
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;
}
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)
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':
case 'i':
case 'c':
case 'k':
+ case '%':
break;
default:
m = g_strdup_printf("Malformed Exec key, "
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:
GQuark *categories; /*!< Array of quarks representing the
application's categories */
+ gulong n_categories; /*!< Number of categories for the app */
ObtLinkAppStartup startup;
gchar *startup_wmclass;
/* 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"))) {
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 */
}
}
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;
+}