save key values based on their value, but we dont know what values they have yet
This commit is contained in:
parent
a1fa5dca08
commit
749d6f0938
1 changed files with 123 additions and 40 deletions
163
obt/ddfile.c
163
obt/ddfile.c
|
@ -25,34 +25,52 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef void (*ObtDDParseGroupFunc)(const gchar *group,
|
typedef struct _ObtDDParse ObtDDParse;
|
||||||
GHashTable *key_hash);
|
typedef struct _ObtDDParseGroup ObtDDParseGroup;
|
||||||
|
|
||||||
typedef struct _ObtDDParseGroup {
|
typedef void (*ObtDDParseGroupFunc)(gchar *key, const gchar *val,
|
||||||
|
ObtDDParse *parse, gboolean *error);
|
||||||
|
|
||||||
|
struct _ObtDDParseGroup {
|
||||||
gchar *name;
|
gchar *name;
|
||||||
gboolean seen;
|
gboolean seen;
|
||||||
ObtDDParseGroupFunc func;
|
ObtDDParseGroupFunc key_func;
|
||||||
/* the key is a string (a key in the .desktop).
|
/* the key is a string (a key inside the group in the .desktop).
|
||||||
the value is a strings (a value in the .desktop) */
|
the value is an ObtDDParseValue */
|
||||||
GHashTable *key_hash;
|
GHashTable *key_hash;
|
||||||
} ObtDDParseGroup;
|
};
|
||||||
|
|
||||||
typedef struct _ObtDDParse {
|
struct _ObtDDParse {
|
||||||
gchar *filename;
|
gchar *filename;
|
||||||
gulong lineno;
|
gulong lineno;
|
||||||
ObtDDParseGroup *group;
|
ObtDDParseGroup *group;
|
||||||
/* the key is a group name, the value is a ObtDDParseGroup */
|
/* the key is a group name, the value is a ObtDDParseGroup */
|
||||||
GHashTable *group_hash;
|
GHashTable *group_hash;
|
||||||
} ObtDDParse;
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DATA_STRING,
|
DATA_STRING,
|
||||||
DATA_LOCALESTRING,
|
DATA_LOCALESTRING,
|
||||||
|
DATA_STRINGS,
|
||||||
|
DATA_LOCALESTRINGS,
|
||||||
DATA_BOOLEAN,
|
DATA_BOOLEAN,
|
||||||
DATA_NUMERIC,
|
DATA_NUMERIC,
|
||||||
NUM_DATA_TYPES
|
NUM_DATA_TYPES
|
||||||
} ObtDDDataType;
|
} ObtDDDataType;
|
||||||
|
|
||||||
|
typedef struct _ObtDDParseValue {
|
||||||
|
ObtDDDataType type;
|
||||||
|
union _ObtDDParseValueValue {
|
||||||
|
gchar *string;
|
||||||
|
struct _ObtDDParseValueStrings {
|
||||||
|
gchar *s;
|
||||||
|
gulong n;
|
||||||
|
} strings;
|
||||||
|
gboolean boolean;
|
||||||
|
gfloat numeric;
|
||||||
|
} value;
|
||||||
|
} ObtDDParseValue;
|
||||||
|
|
||||||
struct _ObtDDFile {
|
struct _ObtDDFile {
|
||||||
guint ref;
|
guint ref;
|
||||||
|
|
||||||
|
@ -63,7 +81,7 @@ struct _ObtDDFile {
|
||||||
gchar *icon; /*!< Name/path for an icon for the object */
|
gchar *icon; /*!< Name/path for an icon for the object */
|
||||||
|
|
||||||
union _ObtDDFileData {
|
union _ObtDDFileData {
|
||||||
struct {
|
struct _ObtDDFileApp {
|
||||||
gchar *exec; /*!< Executable to run for the app */
|
gchar *exec; /*!< Executable to run for the app */
|
||||||
gchar *wdir; /*!< Working dir to run the app in */
|
gchar *wdir; /*!< Working dir to run the app in */
|
||||||
gboolean term; /*!< Run the app in a terminal or not */
|
gboolean term; /*!< Run the app in a terminal or not */
|
||||||
|
@ -76,22 +94,43 @@ struct _ObtDDFile {
|
||||||
ObtDDFileAppStartup startup;
|
ObtDDFileAppStartup startup;
|
||||||
gchar *startup_wmclass;
|
gchar *startup_wmclass;
|
||||||
} app;
|
} app;
|
||||||
struct {
|
struct _ObtDDFileLink {
|
||||||
gchar *url;
|
gchar *url;
|
||||||
} link;
|
} link;
|
||||||
struct {
|
struct _ObtDDFileDir {
|
||||||
} dir;
|
} dir;
|
||||||
} d;
|
} d;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void value_free(ObtDDParseValue *v)
|
||||||
|
{
|
||||||
|
switch (v->type) {
|
||||||
|
case DATA_STRING:
|
||||||
|
case DATA_LOCALESTRING:
|
||||||
|
g_free(v->value.string); break;
|
||||||
|
case DATA_STRINGS:
|
||||||
|
case DATA_LOCALESTRINGS:
|
||||||
|
g_free(v->value.strings.s);
|
||||||
|
v->value.strings.n = 0;
|
||||||
|
break;
|
||||||
|
case DATA_BOOLEAN:
|
||||||
|
break;
|
||||||
|
case DATA_NUMERIC:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
g_slice_free(ObtDDParseValue, v);
|
||||||
|
}
|
||||||
|
|
||||||
static ObtDDParseGroup* group_new(gchar *name, ObtDDParseGroupFunc f)
|
static ObtDDParseGroup* group_new(gchar *name, ObtDDParseGroupFunc f)
|
||||||
{
|
{
|
||||||
ObtDDParseGroup *g = g_slice_new(ObtDDParseGroup);
|
ObtDDParseGroup *g = g_slice_new(ObtDDParseGroup);
|
||||||
g->name = name;
|
g->name = name;
|
||||||
g->func = f;
|
g->key_func = f;
|
||||||
g->seen = FALSE;
|
g->seen = FALSE;
|
||||||
g->key_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
|
g->key_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||||
g_free, g_free);
|
g_free, (GDestroyNotify)value_free);
|
||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,8 +156,14 @@ static void parse_error(const gchar *m, const ObtDDParse *const parse,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reads an input string, strips out invalid stuff, and parses
|
/* reads an input string, strips out invalid stuff, and parses
|
||||||
backslash-stuff */
|
backslash-stuff
|
||||||
static gchar* parse_string(const gchar *in, gboolean locale,
|
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_string(const gchar *in,
|
||||||
|
gboolean locale,
|
||||||
|
gulong *nstrings,
|
||||||
const ObtDDParse *const parse,
|
const ObtDDParse *const parse,
|
||||||
gboolean *error)
|
gboolean *error)
|
||||||
{
|
{
|
||||||
|
@ -143,6 +188,8 @@ static gchar* parse_string(const gchar *in, gboolean locale,
|
||||||
else if (!g_utf8_validate(in, bytes, &end))
|
else if (!g_utf8_validate(in, bytes, &end))
|
||||||
parse_error("Invalid bytes in localestring", parse, error);
|
parse_error("Invalid bytes in localestring", parse, error);
|
||||||
|
|
||||||
|
if (nstrings) *nstrings = 1;
|
||||||
|
|
||||||
out = g_new(char, bytes + 1);
|
out = g_new(char, bytes + 1);
|
||||||
i = in; o = out;
|
i = in; o = out;
|
||||||
backslash = FALSE;
|
backslash = FALSE;
|
||||||
|
@ -154,6 +201,7 @@ static gchar* parse_string(const gchar *in, gboolean locale,
|
||||||
case 'n': *o++ = '\n'; break;
|
case 'n': *o++ = '\n'; break;
|
||||||
case 't': *o++ = '\t'; break;
|
case 't': *o++ = '\t'; break;
|
||||||
case 'r': *o++ = '\r'; break;
|
case 'r': *o++ = '\r'; break;
|
||||||
|
case ';': *o++ = ';'; break;
|
||||||
case '\\': *o++ = '\\'; break;
|
case '\\': *o++ = '\\'; break;
|
||||||
default:
|
default:
|
||||||
parse_error((locale ?
|
parse_error((locale ?
|
||||||
|
@ -165,6 +213,10 @@ static gchar* parse_string(const gchar *in, gboolean locale,
|
||||||
}
|
}
|
||||||
else if (*i == '\\')
|
else if (*i == '\\')
|
||||||
backslash = TRUE;
|
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 */
|
/* avoid ascii control characters */
|
||||||
parse_error("Found control character in string", parse, error);
|
parse_error("Found control character in string", parse, error);
|
||||||
|
@ -190,17 +242,64 @@ static gboolean parse_bool(const gchar *in, const ObtDDParse *const parse,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float parse_numeric(const gchar *in, const ObtDDParse *const parse,
|
static gfloat parse_numeric(const gchar *in, const ObtDDParse *const parse,
|
||||||
gboolean *error)
|
gboolean *error)
|
||||||
{
|
{
|
||||||
float out = 0;
|
gfloat out = 0;
|
||||||
if (sscanf(in, "%f", &out) == 0)
|
if (sscanf(in, "%f", &out) == 0)
|
||||||
parse_error("Invalid numeric value", parse, error);
|
parse_error("Invalid numeric value", parse, error);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean parse_file_line(FILE *f, gchar **buf, gulong *size, gulong *read,
|
static void parse_group_desktop_entry(gchar *key, const gchar *val,
|
||||||
ObtDDParse *parse, gboolean *error)
|
ObtDDParse *parse, gboolean *error)
|
||||||
|
{
|
||||||
|
ObtDDParseValue v, *pv;
|
||||||
|
|
||||||
|
/* figure out value type */
|
||||||
|
v.type = NUM_DATA_TYPES;
|
||||||
|
|
||||||
|
/* parse the value */
|
||||||
|
|
||||||
|
switch (v.type) {
|
||||||
|
case DATA_STRING:
|
||||||
|
v.value.string = parse_string(val, FALSE, NULL, parse, error);
|
||||||
|
g_assert(v.value.string);
|
||||||
|
break;
|
||||||
|
case DATA_LOCALESTRING:
|
||||||
|
v.value.string = parse_string(val, TRUE, NULL, parse, error);
|
||||||
|
g_assert(v.value.string);
|
||||||
|
break;
|
||||||
|
case DATA_STRINGS:
|
||||||
|
v.value.strings.s = parse_string(val, FALSE, &v.value.strings.n,
|
||||||
|
parse, error);
|
||||||
|
g_assert(v.value.strings.s);
|
||||||
|
g_assert(v.value.strings.n);
|
||||||
|
break;
|
||||||
|
case DATA_LOCALESTRINGS:
|
||||||
|
v.value.strings.s = parse_string(val, TRUE, &v.value.strings.n,
|
||||||
|
parse, error);
|
||||||
|
g_assert(v.value.strings.s);
|
||||||
|
g_assert(v.value.strings.n);
|
||||||
|
break;
|
||||||
|
case DATA_BOOLEAN:
|
||||||
|
v.value.boolean = parse_bool(val, parse, error);
|
||||||
|
break;
|
||||||
|
case DATA_NUMERIC:
|
||||||
|
v.value.numeric = parse_numeric(val, parse, error);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
pv = g_slice_new(ObtDDParseValue);
|
||||||
|
*pv = v;
|
||||||
|
g_hash_table_insert(parse->group->key_hash, key, pv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean parse_file_line(FILE *f, gchar **buf,
|
||||||
|
gulong *size, gulong *read,
|
||||||
|
ObtDDParse *parse, gboolean *error)
|
||||||
{
|
{
|
||||||
const gulong BUFMUL = 80;
|
const gulong BUFMUL = 80;
|
||||||
size_t ret;
|
size_t ret;
|
||||||
|
@ -334,7 +433,7 @@ static void parse_key_value(const gchar *buf, gulong len,
|
||||||
ObtDDParse *parse, gboolean *error)
|
ObtDDParse *parse, gboolean *error)
|
||||||
{
|
{
|
||||||
gulong i, keyend, valstart, eq;
|
gulong i, keyend, valstart, eq;
|
||||||
char *key, *val;
|
char *key;
|
||||||
|
|
||||||
/* find the end of the key */
|
/* find the end of the key */
|
||||||
for (i = 0; i < len; ++i)
|
for (i = 0; i < len; ++i)
|
||||||
|
@ -377,22 +476,14 @@ static void parse_key_value(const gchar *buf, gulong len,
|
||||||
}
|
}
|
||||||
|
|
||||||
key = g_strndup(buf, keyend);
|
key = g_strndup(buf, keyend);
|
||||||
val = g_strndup(buf+valstart, len-valstart);
|
|
||||||
if (g_hash_table_lookup(parse->group->key_hash, key)) {
|
if (g_hash_table_lookup(parse->group->key_hash, key)) {
|
||||||
parse_error("Duplicate key found", parse, error);
|
parse_error("Duplicate key found", parse, error);
|
||||||
g_free(key);
|
g_free(key);
|
||||||
g_free(val);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
g_hash_table_insert(parse->group->key_hash, key, val);
|
g_print("Found key/value %s=%s.\n", key, buf+valstart);
|
||||||
g_print("Found key/value %s=%s.\n", key, val);
|
if (parse->group->key_func)
|
||||||
}
|
parse->group->key_func(key, buf+valstart, parse, error);
|
||||||
|
|
||||||
void foreach_group(gpointer pkey, gpointer pvalue, gpointer user_data)
|
|
||||||
{
|
|
||||||
gchar *name = pkey;
|
|
||||||
ObtDDParseGroup *g = pvalue;
|
|
||||||
if (g->func) g->func(name, g->key_hash);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean parse_file(ObtDDFile *dd, FILE *f, ObtDDParse *parse)
|
static gboolean parse_file(ObtDDFile *dd, FILE *f, ObtDDParse *parse)
|
||||||
|
@ -417,18 +508,10 @@ static gboolean parse_file(ObtDDFile *dd, FILE *f, ObtDDParse *parse)
|
||||||
++parse->lineno;
|
++parse->lineno;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_hash_table_foreach(parse->group_hash, foreach_group, NULL);
|
|
||||||
|
|
||||||
if (buf) g_free(buf);
|
if (buf) g_free(buf);
|
||||||
return !error;
|
return !error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_group_desktop_entry(const gchar *group,
|
|
||||||
GHashTable *keys)
|
|
||||||
{
|
|
||||||
g_print("Parsing group %s\n", group);
|
|
||||||
}
|
|
||||||
|
|
||||||
ObtDDFile* obt_ddfile_new_from_file(const gchar *name, GSList *paths)
|
ObtDDFile* obt_ddfile_new_from_file(const gchar *name, GSList *paths)
|
||||||
{
|
{
|
||||||
ObtDDFile *dd;
|
ObtDDFile *dd;
|
||||||
|
|
Loading…
Reference in a new issue