X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;ds=sidebyside;f=obt%2Fddfile.c;h=a4a7735df0409c25bf4a8d5567f62b6977dbb3f3;hb=00fb4d392fd25641f877c658463ccfd3286003bf;hp=e32dff3ee4623fb7bacfdc715341705cc29eb91f;hpb=159a3cb3b1dcf0b3d1cb3a194a181d4e6aea57a4;p=chaz%2Fopenbox diff --git a/obt/ddfile.c b/obt/ddfile.c index e32dff3e..a4a7735d 100644 --- a/obt/ddfile.c +++ b/obt/ddfile.c @@ -26,19 +26,22 @@ #endif typedef void (*ObtDDParseGroupFunc)(const gchar *group, - const gchar *key, - const gchar *value); + GHashTable *key_hash); typedef struct _ObtDDParseGroup { gchar *name; gboolean seen; ObtDDParseGroupFunc func; + /* the key is a string (a key in the .desktop). + the value is a strings (a value in the .desktop) */ + GHashTable *key_hash; } ObtDDParseGroup; typedef struct _ObtDDParse { gchar *filename; gulong lineno; ObtDDParseGroup *group; + /* the key is a group name, the value is a ObtDDParseGroup */ GHashTable *group_hash; } ObtDDParse; @@ -84,6 +87,7 @@ struct _ObtDDFile { static void group_free(ObtDDParseGroup *g) { g_free(g->name); + g_hash_table_destroy(g->key_hash); g_slice_free(ObtDDParseGroup, g); } @@ -306,6 +310,8 @@ static void parse_group(const gchar *buf, gulong len, g = g_slice_new(ObtDDParseGroup); g->name = group; g->func = NULL; + g->key_hash = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); g_hash_table_insert(parse->group_hash, group, g); } else @@ -317,6 +323,64 @@ static void parse_group(const gchar *buf, gulong len, } } +static void parse_key_value(const gchar *buf, gulong len, + ObtDDParse *parse, gboolean *error) +{ + gulong i, keyend, valstart, eq; + char *key, *val; + + /* find the end of the key */ + for (i = 0; i < len; ++i) + if (!(((guchar)buf[i] >= 'A' && (guchar)buf[i] <= 'Z') || + ((guchar)buf[i] >= 'a' && (guchar)buf[i] <= 'z') || + ((guchar)buf[i] >= '0' && (guchar)buf[i] <= '9') || + ((guchar)buf[i] == '-'))) { + /* not part of the key */ + keyend = i; + break; + } + if (keyend < 1) { + parse_error("Empty key", parse, error); + return; + } + /* find the = character */ + for (i = keyend; i < len; ++i) { + if (buf[i] == '=') { + eq = i; + break; + } + else if (buf[i] != ' ') { + parse_error("Invalid character in key name", parse, error); + return ; + } + } + if (i == len) { + parse_error("Key without value found", parse, error); + return; + } + /* find the start of the value */ + for (i = eq+1; i < len; ++i) + if (buf[i] != ' ') { + valstart = i; + break; + } + if (i == len) { + parse_error("Empty value found", parse, error); + return; + } + + key = g_strndup(buf, keyend); + val = g_strndup(buf+valstart, len-valstart); + if (g_hash_table_lookup(parse->group->key_hash, key)) { + parse_error("Duplicate key found", parse, error); + g_free(key); + g_free(val); + return; + } + g_hash_table_insert(parse->group->key_hash, key, val); + g_print("Found key/value %s=%s.\n", key, val); +} + static gboolean parse_file(ObtDDFile *dd, FILE *f, ObtDDParse *parse) { gchar *buf = NULL; @@ -330,6 +394,12 @@ static gboolean parse_file(ObtDDFile *dd, FILE *f, ObtDDParse *parse) ; /* ignore comment lines */ else if (buf[0] == '[' && buf[len-1] == ']') parse_group(buf, len, parse, &error); + else if (!parse->group) + /* just ignore keys outside of groups */ + parse_error("Key found before group", parse, NULL); + else + /* ignore errors in key-value pairs and continue */ + parse_key_value(buf, len, parse, NULL); ++parse->lineno; } @@ -343,6 +413,7 @@ ObtDDFile* obt_ddfile_new_from_file(const gchar *name, GSList *paths) ObtDDParse parse; GSList *it; FILE *f; + gboolean success; dd = g_slice_new(ObtDDFile); dd->ref = 1; @@ -350,23 +421,23 @@ ObtDDFile* obt_ddfile_new_from_file(const gchar *name, GSList *paths) parse.filename = NULL; parse.lineno = 0; parse.group = NULL; - /* hashtable keys are group names, value is a ObtDDParseGroup */ parse.group_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify)group_free); - f = NULL; - for (it = paths; it && !f; it = g_slist_next(it)) { + success = FALSE; + for (it = paths; it && !success; it = g_slist_next(it)) { gchar *path = g_strdup_printf("%s/%s", (char*)it->data, name); if ((f = fopen(path, "r"))) { parse.filename = path; parse.lineno = 1; - if (!parse_file(dd, f, &parse)) f = NULL; + success = parse_file(dd, f, &parse); + fclose(f); } g_free(path); } - if (!f) { + if (!success) { obt_ddfile_unref(dd); dd = NULL; }