ui/common/properties.c

changeset 115
e57ca2747782
parent 110
c00e968d018b
equal deleted inserted replaced
114:3da24640513a 115:e57ca2747782
42 #include "properties.h" 42 #include "properties.h"
43 #include <cx/string.h> 43 #include <cx/string.h>
44 #include <cx/buffer.h> 44 #include <cx/buffer.h>
45 45
46 #include <cx/hash_map.h> 46 #include <cx/hash_map.h>
47 #include "ucx_properties.h" 47 #include <cx/properties.h>
48 48
49 static CxMap *application_properties; 49 static CxMap *application_properties;
50 static CxMap *language; 50 static CxMap *language;
51 51
52 #ifndef UI_COCOA 52 #ifndef UI_COCOA
53 53
54 static char *locales_dir; 54 static char *locales_dir;
55 static char *pixmaps_dir; 55 static char *pixmaps_dir;
56 56
57 #endif 57 static UiBool use_xdg_config_home = TRUE;
58 58
59 #endif
60
61 static UiBool load_on_startup = TRUE;
62 static void *properties_data = NULL;
63 static size_t properties_data_length = 0;
64
65 void ui_load_properties_file_on_startup(UiBool enable) {
66 load_on_startup = enable;
67 }
68
69 void ui_set_properties_data(const char *str, size_t len) {
70 if(str && len > 0) {
71 properties_data = malloc(len);
72 memcpy(properties_data, str, len);
73 } else {
74 properties_data = NULL;
75 properties_data_length = 0;
76 }
77 }
59 78
60 char* ui_getappdir(void) { 79 char* ui_getappdir(void) {
61 if(ui_appname() == NULL) { 80 if(ui_appname() == NULL) {
62 return NULL; 81 return NULL;
63 } 82 }
70 #define UI_ENV_HOME "HOME" 89 #define UI_ENV_HOME "HOME"
71 #else 90 #else
72 #define UI_PATH_SEPARATOR '\\' 91 #define UI_PATH_SEPARATOR '\\'
73 #define UI_ENV_HOME "USERPROFILE" 92 #define UI_ENV_HOME "USERPROFILE"
74 #endif 93 #endif
94
95 #define UI_XDG_CONFIG_HOME_VAR "XDG_CONFIG_HOME"
75 96
76 char* ui_configfile(const char *name) { 97 char* ui_configfile(const char *name) {
77 const char *appname = ui_appname(); 98 const char *appname = ui_appname();
78 if(!appname) { 99 if(!appname) {
79 return NULL; 100 return NULL;
100 cxBufferPutString(&buf, "Library/Application Support/"); 121 cxBufferPutString(&buf, "Library/Application Support/");
101 #elif defined(_WIN32) 122 #elif defined(_WIN32)
102 // on Windows the app dir is $USERPROFILE/AppData/Local/$APPNAME/ 123 // on Windows the app dir is $USERPROFILE/AppData/Local/$APPNAME/
103 cxBufferPutString(&buf, "AppData\\Local\\"); 124 cxBufferPutString(&buf, "AppData\\Local\\");
104 #else 125 #else
105 // app dir is $HOME/.$APPNAME/ 126 if(use_xdg_config_home) {
106 cxBufferPut(&buf, '.'); 127 // app dir is $HOME/.config/$APPNAME/
128 char *xdghome = getenv(UI_XDG_CONFIG_HOME_VAR);
129 size_t xdghomelen = xdghome ? strlen(xdghome) : 0;
130 if(xdghome && xdghomelen > 0) {
131 cxBufferSeek(&buf, 0, SEEK_SET);
132 cxBufferPutString(&buf, xdghome);
133 if(xdghome[xdghomelen-1] != '/') {
134 cxBufferPut(&buf, '/');
135 }
136 } else {
137 cxBufferPutString(&buf, ".config/");
138 }
139 } else {
140 cxBufferPut(&buf, '.');
141 }
142
107 #endif 143 #endif
108 cxBufferPutString(&buf, appname); 144 cxBufferPutString(&buf, appname);
109 cxBufferPut(&buf, UI_PATH_SEPARATOR); 145 cxBufferPut(&buf, UI_PATH_SEPARATOR);
110 146
111 // add file name 147 // add file name
124 #else 160 #else
125 return mkdir(path, S_IRWXU); 161 return mkdir(path, S_IRWXU);
126 #endif 162 #endif
127 } 163 }
128 164
165 static int load_properties(FILE *file, CxMap *map) {
166 CxProperties prop;
167 cxPropertiesInitDefault(&prop);
168 char buf[8192];
169 size_t r;
170 CxPropertiesStatus status = CX_PROPERTIES_NO_ERROR;
171 while((r = fread(buf, 1, 8192, file)) > 0) {
172 cxPropertiesFilln(&prop, buf, r);
173 cxstring key;
174 cxstring value;
175 while((status = cxPropertiesNext(&prop, &key, &value)) == CX_PROPERTIES_NO_ERROR) {
176 cxMapPut(map, key, cx_strdup(value).ptr);
177 }
178 if(status > CX_PROPERTIES_OK) {
179 break;
180 }
181 }
182 return status <= CX_PROPERTIES_NO_DATA ? 0 : 1;
183 }
184
129 void uic_load_app_properties() { 185 void uic_load_app_properties() {
130 application_properties = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 128); 186 application_properties = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 128);
131 application_properties->collection.simple_destructor = free; 187 application_properties->collection.simple_destructor = free;
132 188
189 if(!load_on_startup) {
190 if(properties_data) {
191 CxProperties prop;
192 cxPropertiesInitDefault(&prop);
193
194 CxPropertiesStatus status = CX_PROPERTIES_NO_ERROR;
195 cxPropertiesFilln(&prop, properties_data, properties_data_length);
196
197 cxstring key;
198 cxstring value;
199 while((status = cxPropertiesNext(&prop, &key, &value)) == CX_PROPERTIES_NO_ERROR) {
200 cxMapPut(application_properties, key, cx_strdup(value).ptr);
201 }
202
203 if(status > CX_PROPERTIES_NO_DATA) {
204 fprintf(stderr, "Error: cannot load properties: %d\n", (int)status);
205 } else {
206 cxMapRehash(application_properties);
207 }
208 }
209 return;
210 }
211
133 if(!ui_appname()) { 212 if(!ui_appname()) {
134 // applications without name cannot load app properties 213 // applications without name cannot load app properties
135 return; 214 return;
136 } 215 }
137 216
138 char *dir = ui_configfile(NULL); 217 char *dir = ui_configfile(NULL);
139 if(!dir) { 218 if(!dir) {
140 return; 219 return;
141 } 220 }
221 size_t len = strlen(dir);
222 if(len < 2) {
223 return;
224 }
142 if(ui_mkdir(dir)) { 225 if(ui_mkdir(dir)) {
226 if(errno == ENOENT) {
227 char *parent = strdup(dir);
228 for(int i=len-2;i>=0;i--) {
229 if(parent[i] == '/') {
230 parent[i] = 0;
231 break;
232 }
233 }
234 // try creating the parent
235 int err = ui_mkdir(parent);
236 if(err) {
237 fprintf(stderr, "Error: Cannot create directory %s: %s\n", parent, strerror(errno));
238 free(parent);
239 free(dir);
240 return;
241 }
242 free(parent);
243
244 // try dir again
245 if(!ui_mkdir(dir)) {
246 errno = EEXIST; // success
247 }
248 }
249
143 if(errno != EEXIST) { 250 if(errno != EEXIST) {
144 fprintf(stderr, "Ui Error: Cannot create directory %s\n", dir); 251 fprintf(stderr, "Error: Cannot create directory %s: %s\n", dir, strerror(errno));
145 free(dir); 252 free(dir);
146 return; 253 return;
147 } 254 }
148 } 255 }
149 free(dir); 256 free(dir);
157 if(!file) { 264 if(!file) {
158 free(path); 265 free(path);
159 return; 266 return;
160 } 267 }
161 268
162 if(ucx_properties_load(application_properties, file)) { 269 if(load_properties(file, application_properties)) {
163 fprintf(stderr, "Ui Error: Cannot load application properties.\n"); 270 fprintf(stderr, "Error: Cannot load application properties.\n");
164 } 271 }
165 272
166 fclose(file); 273 fclose(file);
167 free(path); 274 free(path);
168 } 275 }
179 free(path); 286 free(path);
180 return 1; 287 return 1;
181 } 288 }
182 289
183 int ret = 0; 290 int ret = 0;
184 if(ucx_properties_store(application_properties, file)) { 291 CxMapIterator i = cxMapIterator(application_properties);
185 fprintf(stderr, "Ui Error: Cannot store application properties.\n"); 292 cx_foreach(CxMapEntry *, entry, i) {
186 ret = 1; 293 fprintf(file, "%.*s = %s\n", (int)entry->key->len, (char*)entry->key->data, (char*)entry->value);
187 } 294 }
295
296 cxMapRehash(application_properties);
188 297
189 fclose(file); 298 fclose(file);
190 free(path); 299 free(path);
191 300
192 return ret; 301 return ret;
311 FILE *file = fopen(path, "r"); 420 FILE *file = fopen(path, "r");
312 if(!file) { 421 if(!file) {
313 return 1; 422 return 1;
314 } 423 }
315 424
316 if(ucx_properties_load(lang, file)) { 425 if(load_properties(file, lang)) {
317 fprintf(stderr, "Ui Error: Cannot parse language file: %s.\n", path); 426 fprintf(stderr, "Error: Cannot parse language file: %s.\n", path);
318 } 427 }
319 428
320 fclose(file); 429 fclose(file);
321 430
322 cxMapRehash(lang); 431 cxMapRehash(lang);

mercurial