X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=obt%2Fddparse.c;h=149134d85504a567a0259b8d66b9e22336283c16;hb=aa15563feeee03d7748e7d5279decf60db23fda9;hp=6aee25e72ec5f4a8606bd815746846df592cf5cf;hpb=3121146eccd031a56d410eb48f3002558f41b40a;p=chaz%2Fopenbox diff --git a/obt/ddparse.c b/obt/ddparse.c index 6aee25e7..149134d8 100644 --- a/obt/ddparse.c +++ b/obt/ddparse.c @@ -35,9 +35,19 @@ typedef gboolean (*ObtDDParseValueFunc)(gchar *key, const gchar *val, ObtDDParse *parse, gboolean *error); +enum { + DE_TYPE = 1 << 0, + DE_TYPE_APPLICATION = 1 << 1, + DE_TYPE_LINK = 1 << 2, + DE_NAME = 1 << 3, + DE_EXEC = 1 << 4, + DE_URL = 1 << 5 +}; + struct _ObtDDParse { gchar *filename; gulong lineno; + gulong flags; ObtDDParseGroup *group; /* the key is a group name, the value is a ObtDDParseGroup */ GHashTable *group_hash; @@ -69,17 +79,19 @@ static void parse_error(const gchar *m, const ObtDDParse *const parse, static void parse_value_free(ObtDDParseValue *v) { switch (v->type) { + case OBT_DDPARSE_EXEC: case OBT_DDPARSE_STRING: case OBT_DDPARSE_LOCALESTRING: 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: case OBT_DDPARSE_NUMERIC: - case OBT_DDPARSE_ENUM_APPLICATION: + case OBT_DDPARSE_ENUM_TYPE: + case OBT_DDPARSE_ENVIRONMENTS: break; default: g_assert_not_reached(); @@ -108,44 +120,48 @@ 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) { - const gchar *next = locale ? g_utf8_find_next_char(i, end) : i+1; + const gchar *next; + + /* find the next character in the string */ + if (!locale) next = i+1; + else if (!(next = g_utf8_find_next_char(i, end))) next = end; + if (backslash) { switch(*i) { case 's': *o++ = ' '; break; @@ -164,23 +180,121 @@ 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; } *o = '\0'; - return o; + 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) +{ + const gchar *s; + guint mask = 0; + + s = in; + while (*s) { + switch (*(s++)) { + case 'G': + if (strcmp(s, "NOME") == 0) { + mask |= OBT_LINK_ENV_GNOME; + s += 4; + } + break; + case 'K': + if (strcmp(s, "DE") == 0) { + mask |= OBT_LINK_ENV_KDE; + s += 2; + } + break; + case 'L': + if (strcmp(s, "XDE") == 0) { + mask |= OBT_LINK_ENV_LXDE; + s += 3; + } + break; + case 'R': + if (strcmp(s, "OX") == 0) { + mask |= OBT_LINK_ENV_ROX; + s += 2; + } + break; + case 'X': + if (strcmp(s, "FCE") == 0) { + mask |= OBT_LINK_ENV_XFCE; + s += 3; + } + break; + case 'O': + switch (*(s++)) { + case 'l': + if (strcmp(s, "d") == 0) { + mask |= OBT_LINK_ENV_OLD; + s += 1; + } + break; + case 'P': + if (strcmp(s, "ENBOX") == 0) { + mask |= OBT_LINK_ENV_OPENBOX; + s += 5; + } + break; + } + } + /* find the next string, or the end of the sequence */ + while (*s && *s != ';') ++s; + } + return mask; } static gboolean parse_value_boolean(const gchar *in, @@ -349,9 +463,10 @@ static void parse_key_value(const gchar *buf, gulong len, ((guchar)buf[i] >= '0' && (guchar)buf[i] <= '9') || ((guchar)buf[i] == '-'))) { /* not part of the key */ - keyend = i; break; } + keyend = i; + if (keyend < 1) { parse_error("Empty key", parse, error); return; @@ -441,7 +556,7 @@ static gboolean parse_desktop_entry_value(gchar *key, const gchar *val, break; case 'E': /* Exec */ if (strcmp(key+1, "xec")) return FALSE; - v.type = OBT_DDPARSE_STRING; break; + v.type = OBT_DDPARSE_EXEC; parse->flags |= DE_EXEC; break; case 'G': /* GenericName */ if (strcmp(key+1, "enericName")) return FALSE; v.type = OBT_DDPARSE_LOCALESTRING; break; @@ -458,7 +573,7 @@ static gboolean parse_desktop_entry_value(gchar *key, const gchar *val, switch (key[1]) { case 'a': /* Name */ if (strcmp(key+2, "me")) return FALSE; - v.type = OBT_DDPARSE_LOCALESTRING; break; + v.type = OBT_DDPARSE_LOCALESTRING; parse->flags |= DE_NAME; break; case 'o': switch (key[2]) { case 'D': /* NoDisplay */ @@ -504,14 +619,14 @@ static gboolean parse_desktop_entry_value(gchar *key, const gchar *val, v.type = OBT_DDPARSE_STRING; break; case 'y': /* Type */ if (strcmp(key+2, "pe")) return FALSE; - v.type = OBT_DDPARSE_STRING; break; + v.type = OBT_DDPARSE_ENUM_TYPE; parse->flags |= DE_TYPE; break; default: return FALSE; } break; case 'U': /* URL */ if (strcmp(key+1, "RL")) return FALSE; - v.type = OBT_DDPARSE_STRING; break; + v.type = OBT_DDPARSE_STRING; parse->flags |= DE_URL; break; case 'V': /* MimeType */ if (strcmp(key+1, "ersion")) return FALSE; v.type = OBT_DDPARSE_STRING; break; @@ -521,24 +636,80 @@ static gboolean parse_desktop_entry_value(gchar *key, const gchar *val, /* parse the value */ switch (v.type) { + case OBT_DDPARSE_EXEC: { + gchar *c, *m; + gboolean percent; + gboolean found; + + 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 (percent) { + switch (*c) { + case 'f': + case 'F': + case 'u': + case 'U': + if (found) { + m = g_strdup_printf("Malformed Exec key, " + "extraneous %%%c", *c); + parse_error(m, parse, error); + g_free(m); + } + found = TRUE; + break; + case 'd': + case 'D': + case 'n': + case 'N': + case 'v': + case 'm': + m = g_strdup_printf("Malformed Exec key, " + "uses deprecated %%%c", *c); + parse_error(m, parse, NULL); /* just a warning */ + g_free(m); + break; + case 'i': + case 'c': + case 'k': + case '%': + break; + default: + m = g_strdup_printf("Malformed Exec key, " + "uses unknown %%%c", *c); + 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: @@ -547,11 +718,15 @@ static gboolean parse_desktop_entry_value(gchar *key, const gchar *val, case OBT_DDPARSE_NUMERIC: v.value.numeric = parse_value_numeric(val, parse, error); break; - case OBT_DDPARSE_ENUM_APPLICATION: - if (val[0] == 'A' && strcmp(val+1, "pplication") == 0) + case OBT_DDPARSE_ENUM_TYPE: + if (val[0] == 'A' && strcmp(val+1, "pplication") == 0) { v.value.enumerable = OBT_LINK_TYPE_APPLICATION; - else if (val[0] == 'L' && strcmp(val+1, "ink") == 0) + parse->flags |= DE_TYPE_APPLICATION; + } + else if (val[0] == 'L' && strcmp(val+1, "ink") == 0) { v.value.enumerable = OBT_LINK_TYPE_URL; + parse->flags |= DE_TYPE_LINK; + } else if (val[0] == 'D' && strcmp(val+1, "irectory") == 0) v.value.enumerable = OBT_LINK_TYPE_DIRECTORY; else { @@ -559,6 +734,9 @@ static gboolean parse_desktop_entry_value(gchar *key, const gchar *val, return FALSE; } break; + case OBT_DDPARSE_ENVIRONMENTS: + v.value.environments = parse_value_environments(val, parse, error); + break; default: g_assert_not_reached(); } @@ -596,17 +774,40 @@ GHashTable* obt_ddparse_file(const gchar *name, GSList *paths) if ((f = fopen(path, "r"))) { parse.filename = path; parse.lineno = 1; - success = parse_file(f, &parse); + parse.flags = 0; + if ((success = parse_file(f, &parse))) { + /* check that required keys exist */ + + if (!(parse.flags & DE_TYPE)) { + g_warning("Missing Type key in %s", path); + success = FALSE; + } + if (!(parse.flags & DE_NAME)) { + g_warning("Missing Name key in %s", path); + success = FALSE; + } + if (parse.flags & DE_TYPE_APPLICATION && + !(parse.flags & DE_EXEC)) + { + g_warning("Missing Exec key for Application in %s", + path); + success = FALSE; + } + else if (parse.flags & DE_TYPE_LINK && !(parse.flags & DE_URL)) + { + g_warning("Missing URL key for Link in %s", path); + success = FALSE; + } + } fclose(f); } g_free(path); } if (!success) { g_hash_table_destroy(parse.group_hash); - return NULL; + parse.group_hash = NULL; } - else - return parse.group_hash; + return parse.group_hash; } GHashTable* obt_ddparse_group_keys(ObtDDParseGroup *g)