create a generic tokenizer/sectionizer for the config file. pass off the token to...
[dana/openbox.git] / openbox / parse.c
1 #include "parse.h"
2 #include "config.h"
3
4 static GHashTable *reg = NULL;
5 static ParseFunc func = NULL;
6
7 /* parse tokens from the [openbox] section of the rc file */
8 static void parse_rc_token(ParseTokenType type, union ParseToken token);
9
10 void destkey(gpointer key) { g_free(key); }
11
12 void parse_startup()
13 {
14     reg = g_hash_table_new_full(g_str_hash, g_str_equal, destkey, NULL);
15     func = NULL;
16
17     parse_reg_section("openbox", parse_rc_token);
18 }
19
20 void parse_shutdown()
21 {
22     g_hash_table_destroy(reg);
23 }
24
25 void parse_reg_section(char *section, ParseFunc func)
26 {
27     if (g_hash_table_lookup(reg, section) != NULL)
28         g_warning("duplicate request for section '%s' in the rc file",
29                   section);
30     else
31         g_hash_table_insert(reg, g_ascii_strdown(section, -1), (void*)func);
32 }
33
34 void parse_free_token(ParseTokenType type, union ParseToken token)
35 {
36     switch (type) {
37     case TOKEN_STRING:
38         g_free(token.string);
39         break;
40     case TOKEN_IDENTIFIER:
41         g_free(token.identifier);
42         break;
43     case TOKEN_REAL:
44     case TOKEN_INTEGER:
45     case TOKEN_BOOL:
46     case TOKEN_LBRACKET:
47     case TOKEN_RBRACKET:
48     case TOKEN_LBRACE:
49     case TOKEN_RBRACE:
50     case TOKEN_EQUALS:
51     case TOKEN_COMMA:
52     case TOKEN_NEWLINE:
53         break;
54     }
55 }
56
57 void parse_set_section(char *section)
58 {
59     func = (ParseFunc)g_hash_table_lookup(reg, section);
60 }
61
62 void parse_token(ParseTokenType type, union ParseToken token)
63 {
64     if (func != NULL)
65         func(type, token);
66 }
67
68 static void parse_rc_token(ParseTokenType type, union ParseToken token)
69 {
70     static int got_eq = FALSE;
71     static ParseTokenType got_val = 0;
72     static char *id = NULL, *s = NULL;
73     static int i;
74     static gboolean b;
75
76     if (id == NULL) {
77         if (type == TOKEN_IDENTIFIER) {
78             id = token.identifier;
79             return;
80         } else {
81             yyerror("syntax error");
82         }
83     } else if (!got_eq) {
84         if (type == TOKEN_EQUALS) {
85             got_eq = TRUE;
86             return;
87         } else {
88             yyerror("syntax error");
89         }
90     } else if (!got_val) {
91         if (type == TOKEN_STRING) {
92             s = token.string;
93             got_val = type;
94             return;
95         } else if (type == TOKEN_BOOL) {
96             b = token.bool;
97             got_val = type;
98             return;
99         } else if (type == TOKEN_INTEGER) {
100             i = token.integer;
101             got_val = type;
102             return;
103         } else
104             yyerror("syntax error");
105     } else if (type != TOKEN_NEWLINE) {
106         yyerror("syntax error");
107     } else {
108         ConfigValue v;
109
110         switch (got_val) {
111         case TOKEN_STRING:
112             v.string = s;
113             if (!config_set(id, Config_String, v))
114                 yyerror("invalid value type");
115             break;
116         case TOKEN_BOOL:
117             v.bool = b;
118             if (!config_set(id, Config_Bool, v))
119                 yyerror("invalid value type");
120             break;
121         case TOKEN_INTEGER:
122             v.integer = i;
123             if (!config_set(id, Config_Integer, v))
124                 yyerror("invalid value type");
125             break;
126         default:
127             g_assert_not_reached(); /* unhandled type got parsed */
128         }
129     }
130
131     g_free(id);
132     g_free(s);
133     id = s = NULL;
134     got_eq = FALSE;
135     got_val = 0;
136     parse_free_token(type, token);
137 }