diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/eet/src/examples/eet-data-file_descriptor_01.c | 529 |
1 files changed, 0 insertions, 529 deletions
diff --git a/libraries/eet/src/examples/eet-data-file_descriptor_01.c b/libraries/eet/src/examples/eet-data-file_descriptor_01.c deleted file mode 100644 index 4b5b75f..0000000 --- a/libraries/eet/src/examples/eet-data-file_descriptor_01.c +++ /dev/null | |||
@@ -1,529 +0,0 @@ | |||
1 | /* | ||
2 | * build: gcc -o eet_data_file_descriptor eet-data-file_descriptor.c `pkg-config --cflags --libs eet eina` | ||
3 | */ | ||
4 | #include <Eina.h> | ||
5 | #include <Eet.h> | ||
6 | #include <stdio.h> | ||
7 | #include <limits.h> | ||
8 | #include <sys/types.h> | ||
9 | #include <sys/stat.h> | ||
10 | #include <unistd.h> | ||
11 | |||
12 | // complex real-world structures based on elmdentica database | ||
13 | typedef struct | ||
14 | { | ||
15 | const char *screen_name; | ||
16 | const char *name; | ||
17 | const char *message; | ||
18 | unsigned int id; | ||
19 | unsigned int status_id; | ||
20 | unsigned int date; | ||
21 | unsigned int timeline; | ||
22 | } My_Message; | ||
23 | |||
24 | typedef struct | ||
25 | { | ||
26 | const char *dm_to; | ||
27 | const char *message; | ||
28 | } My_Post; | ||
29 | |||
30 | typedef struct | ||
31 | { | ||
32 | unsigned int id; | ||
33 | const char *name; | ||
34 | Eina_List *messages; | ||
35 | My_Post *posts; | ||
36 | int posts_count; | ||
37 | } My_Account; | ||
38 | |||
39 | typedef struct | ||
40 | { | ||
41 | unsigned int version; // it is recommended to use versioned configuration! | ||
42 | Eina_Hash *accounts; | ||
43 | } My_Cache; | ||
44 | |||
45 | // string that represents the entry in eet file, you might like to have | ||
46 | // different profiles or so in the same file, this is possible with | ||
47 | // different strings | ||
48 | static const char MY_CACHE_FILE_ENTRY[] = "cache"; | ||
49 | |||
50 | // keep the descriptor static global, so it can be | ||
51 | // shared by different functions (load/save) of this and only this | ||
52 | // file. | ||
53 | static Eet_Data_Descriptor *_my_cache_descriptor; | ||
54 | static Eet_Data_Descriptor *_my_account_descriptor; | ||
55 | static Eet_Data_Descriptor *_my_message_descriptor; | ||
56 | static Eet_Data_Descriptor *_my_post_descriptor; | ||
57 | |||
58 | // keep file handle alive, so mmap()ed strings are all alive as well | ||
59 | static Eet_File *_my_cache_file = NULL; | ||
60 | static Eet_Dictionary *_my_cache_dict = NULL; | ||
61 | |||
62 | static void | ||
63 | _my_cache_descriptor_init(void) | ||
64 | { | ||
65 | Eet_Data_Descriptor_Class eddc; | ||
66 | |||
67 | // The FILE variant is good for caches and things that are just | ||
68 | // appended, but needs to take care when changing strings and files must | ||
69 | // be kept open so mmap()ed strings will be kept alive. | ||
70 | EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, My_Cache); | ||
71 | _my_cache_descriptor = eet_data_descriptor_file_new(&eddc); | ||
72 | |||
73 | EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, My_Account); | ||
74 | _my_account_descriptor = eet_data_descriptor_file_new(&eddc); | ||
75 | |||
76 | EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, My_Message); | ||
77 | _my_message_descriptor = eet_data_descriptor_file_new(&eddc); | ||
78 | |||
79 | EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, My_Post); | ||
80 | _my_post_descriptor = eet_data_descriptor_file_new(&eddc); | ||
81 | |||
82 | // Describe the members to be saved: | ||
83 | // Use a temporary macro so we don't type a lot, also avoid errors: | ||
84 | |||
85 | #define ADD_BASIC(member, eet_type) \ | ||
86 | EET_DATA_DESCRIPTOR_ADD_BASIC \ | ||
87 | (_my_message_descriptor, My_Message, # member, member, eet_type) | ||
88 | ADD_BASIC(screen_name, EET_T_STRING); | ||
89 | ADD_BASIC(name, EET_T_STRING); | ||
90 | ADD_BASIC(message, EET_T_STRING); | ||
91 | ADD_BASIC(id, EET_T_UINT); | ||
92 | ADD_BASIC(status_id, EET_T_UINT); | ||
93 | ADD_BASIC(date, EET_T_UINT); | ||
94 | ADD_BASIC(timeline, EET_T_UINT); | ||
95 | #undef ADD_BASIC | ||
96 | |||
97 | #define ADD_BASIC(member, eet_type) \ | ||
98 | EET_DATA_DESCRIPTOR_ADD_BASIC \ | ||
99 | (_my_post_descriptor, My_Post, # member, member, eet_type) | ||
100 | ADD_BASIC(dm_to, EET_T_STRING); | ||
101 | ADD_BASIC(message, EET_T_STRING); | ||
102 | #undef ADD_BASIC | ||
103 | |||
104 | #define ADD_BASIC(member, eet_type) \ | ||
105 | EET_DATA_DESCRIPTOR_ADD_BASIC \ | ||
106 | (_my_account_descriptor, My_Account, # member, member, eet_type) | ||
107 | ADD_BASIC(name, EET_T_STRING); | ||
108 | ADD_BASIC(id, EET_T_UINT); | ||
109 | #undef ADD_BASIC | ||
110 | |||
111 | EET_DATA_DESCRIPTOR_ADD_LIST | ||
112 | (_my_account_descriptor, My_Account, "messages", messages, | ||
113 | _my_message_descriptor); | ||
114 | EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY | ||
115 | (_my_account_descriptor, My_Account, "posts", posts, | ||
116 | _my_post_descriptor); | ||
117 | |||
118 | #define ADD_BASIC(member, eet_type) \ | ||
119 | EET_DATA_DESCRIPTOR_ADD_BASIC \ | ||
120 | (_my_cache_descriptor, My_Cache, # member, member, eet_type) | ||
121 | ADD_BASIC(version, EET_T_UINT); | ||
122 | #undef ADD_BASIC | ||
123 | |||
124 | EET_DATA_DESCRIPTOR_ADD_HASH | ||
125 | (_my_cache_descriptor, My_Cache, "accounts", accounts, | ||
126 | _my_account_descriptor); | ||
127 | } /* _my_cache_descriptor_init */ | ||
128 | |||
129 | static void | ||
130 | _my_cache_descriptor_shutdown(void) | ||
131 | { | ||
132 | eet_data_descriptor_free(_my_cache_descriptor); | ||
133 | eet_data_descriptor_free(_my_account_descriptor); | ||
134 | eet_data_descriptor_free(_my_message_descriptor); | ||
135 | eet_data_descriptor_free(_my_post_descriptor); | ||
136 | } /* _my_cache_descriptor_shutdown */ | ||
137 | |||
138 | // need to check if the pointer came from mmaped area in eet_dictionary | ||
139 | // or it was allocated with eina_stringshare_add() | ||
140 | static void | ||
141 | _eet_string_free(const char *str) | ||
142 | { | ||
143 | if (!str) | ||
144 | return; | ||
145 | |||
146 | if ((_my_cache_dict) && (eet_dictionary_string_check(_my_cache_dict, str))) | ||
147 | return; | ||
148 | |||
149 | eina_stringshare_del(str); | ||
150 | } /* _eet_string_free */ | ||
151 | |||
152 | static My_Message * | ||
153 | _my_message_new(const char *message) | ||
154 | { | ||
155 | My_Message *msg = calloc(1, sizeof(My_Message)); | ||
156 | if (!msg) | ||
157 | { | ||
158 | fprintf(stderr, "ERROR: could not calloc My_Message\n"); | ||
159 | return NULL; | ||
160 | } | ||
161 | |||
162 | msg->message = eina_stringshare_add(message); | ||
163 | return msg; | ||
164 | } /* _my_message_new */ | ||
165 | |||
166 | static void | ||
167 | _my_message_free(My_Message *msg) | ||
168 | { | ||
169 | _eet_string_free(msg->screen_name); | ||
170 | _eet_string_free(msg->name); | ||
171 | _eet_string_free(msg->message); | ||
172 | free(msg); | ||
173 | } /* _my_message_free */ | ||
174 | |||
175 | static Eina_Bool | ||
176 | _my_post_add(My_Account *acc, | ||
177 | const char *message) | ||
178 | { | ||
179 | int new_count = acc->posts_count + 1; | ||
180 | My_Post *post = realloc(acc->posts, new_count * sizeof(My_Post)); | ||
181 | if (!post) | ||
182 | { | ||
183 | fprintf(stderr, "ERROR: could add My_Post\n"); | ||
184 | return EINA_FALSE; | ||
185 | } | ||
186 | |||
187 | post[acc->posts_count].message = eina_stringshare_add(message); | ||
188 | post[acc->posts_count].dm_to = NULL; | ||
189 | acc->posts_count = new_count; | ||
190 | acc->posts = post; | ||
191 | return EINA_TRUE; | ||
192 | } /* _my_post_new */ | ||
193 | |||
194 | static void | ||
195 | _my_post_free(My_Post *post) | ||
196 | { | ||
197 | _eet_string_free(post->dm_to); | ||
198 | _eet_string_free(post->message); | ||
199 | } /* _my_post_free */ | ||
200 | |||
201 | static My_Account * | ||
202 | _my_account_new(const char *name) | ||
203 | { | ||
204 | My_Account *acc = calloc(1, sizeof(My_Account)); | ||
205 | if (!acc) | ||
206 | { | ||
207 | fprintf(stderr, "ERROR: could not calloc My_Account\n"); | ||
208 | return NULL; | ||
209 | } | ||
210 | |||
211 | acc->name = eina_stringshare_add(name); | ||
212 | return acc; | ||
213 | } /* _my_account_new */ | ||
214 | |||
215 | static void | ||
216 | _my_account_free(My_Account *acc) | ||
217 | { | ||
218 | My_Message *m; | ||
219 | int i; | ||
220 | |||
221 | _eet_string_free(acc->name); | ||
222 | |||
223 | EINA_LIST_FREE(acc->messages, m) | ||
224 | _my_message_free(m); | ||
225 | |||
226 | for (i = 0; i < acc->posts_count; i++) | ||
227 | _my_post_free(&acc->posts[i]); | ||
228 | free(acc->posts); | ||
229 | |||
230 | free(acc); | ||
231 | } /* _my_account_free */ | ||
232 | |||
233 | static My_Cache * | ||
234 | _my_cache_new(void) | ||
235 | { | ||
236 | My_Cache *my_cache = calloc(1, sizeof(My_Cache)); | ||
237 | if (!my_cache) | ||
238 | { | ||
239 | fprintf(stderr, "ERROR: could not calloc My_Cache\n"); | ||
240 | return NULL; | ||
241 | } | ||
242 | |||
243 | my_cache->accounts = eina_hash_string_small_new(NULL); | ||
244 | |||
245 | my_cache->version = 1; | ||
246 | return my_cache; | ||
247 | } /* _my_cache_new */ | ||
248 | |||
249 | static Eina_Bool | ||
250 | _my_cache_account_free_cb(const Eina_Hash *hash, | ||
251 | const void *key, | ||
252 | void *data, | ||
253 | void *fdata) | ||
254 | { | ||
255 | _my_account_free(data); | ||
256 | return EINA_TRUE; | ||
257 | } | ||
258 | |||
259 | static void | ||
260 | _my_cache_free(My_Cache *my_cache) | ||
261 | { | ||
262 | My_Account *acc; | ||
263 | eina_hash_foreach(my_cache->accounts, _my_cache_account_free_cb, NULL); | ||
264 | eina_hash_free(my_cache->accounts); | ||
265 | free(my_cache); | ||
266 | } /* _my_cache_free */ | ||
267 | |||
268 | static My_Account * | ||
269 | _my_cache_account_find(My_Cache *my_cache, | ||
270 | const char *name) | ||
271 | { | ||
272 | return eina_hash_find(my_cache->accounts, name); | ||
273 | } /* _my_cache_account_find */ | ||
274 | |||
275 | static My_Cache * | ||
276 | _my_cache_load(const char *filename) | ||
277 | { | ||
278 | My_Cache *my_cache; | ||
279 | Eet_File *ef = eet_open(filename, EET_FILE_MODE_READ); | ||
280 | if (!ef) | ||
281 | { | ||
282 | fprintf(stderr, "ERROR: could not open '%s' for read\n", filename); | ||
283 | return NULL; | ||
284 | } | ||
285 | |||
286 | my_cache = eet_data_read(ef, _my_cache_descriptor, MY_CACHE_FILE_ENTRY); | ||
287 | if (!my_cache) | ||
288 | { | ||
289 | eet_close(ef); | ||
290 | return NULL; | ||
291 | } | ||
292 | |||
293 | if (my_cache->version < 1) | ||
294 | { | ||
295 | fprintf(stderr, | ||
296 | "WARNING: version %#x was too old, upgrading it to %#x\n", | ||
297 | my_cache->version, 1); | ||
298 | |||
299 | my_cache->version = 1; | ||
300 | } | ||
301 | |||
302 | if (_my_cache_file) | ||
303 | eet_close(_my_cache_file); | ||
304 | |||
305 | _my_cache_file = ef; | ||
306 | _my_cache_dict = eet_dictionary_get(ef); | ||
307 | |||
308 | return my_cache; | ||
309 | } /* _my_cache_load */ | ||
310 | |||
311 | static Eina_Bool | ||
312 | _my_cache_save(const My_Cache *my_cache, | ||
313 | const char *filename) | ||
314 | { | ||
315 | char tmp[PATH_MAX]; | ||
316 | Eet_File *ef; | ||
317 | Eina_Bool ret; | ||
318 | unsigned int i, len; | ||
319 | struct stat st; | ||
320 | |||
321 | len = eina_strlcpy(tmp, filename, sizeof(tmp)); | ||
322 | if (len + 12 >= (int)sizeof(tmp)) | ||
323 | { | ||
324 | fprintf(stderr, "ERROR: file name is too big: %s\n", filename); | ||
325 | return EINA_FALSE; | ||
326 | } | ||
327 | |||
328 | i = 0; | ||
329 | do | ||
330 | { | ||
331 | snprintf(tmp + len, 12, ".%u", i); | ||
332 | i++; | ||
333 | } | ||
334 | while (stat(tmp, &st) == 0); | ||
335 | |||
336 | ef = eet_open(tmp, EET_FILE_MODE_WRITE); | ||
337 | if (!ef) | ||
338 | { | ||
339 | fprintf(stderr, "ERROR: could not open '%s' for write\n", tmp); | ||
340 | return EINA_FALSE; | ||
341 | } | ||
342 | |||
343 | ret = eet_data_write | ||
344 | (ef, _my_cache_descriptor, MY_CACHE_FILE_ENTRY, my_cache, EINA_TRUE); | ||
345 | |||
346 | // VERY IMPORTANT NOTE: | ||
347 | // after eet_close(), all strings mmaped from file will be GONE, invalid! | ||
348 | // you'll need to free the old cache and open the new one. | ||
349 | // For cache this is okay, as you should be saving not so often or just | ||
350 | // at end. | ||
351 | // | ||
352 | // This is a trade off, you save memory by using mmap()ed strings, but | ||
353 | // you have to care about this. | ||
354 | eet_close(ef); | ||
355 | |||
356 | if (ret) | ||
357 | { | ||
358 | unlink(filename); | ||
359 | rename(tmp, filename); | ||
360 | } | ||
361 | |||
362 | return ret; | ||
363 | } /* _my_cache_save */ | ||
364 | |||
365 | int | ||
366 | main(int argc, | ||
367 | char *argv[]) | ||
368 | { | ||
369 | My_Cache *my_cache; | ||
370 | const Eina_List *l_acc; | ||
371 | Eina_Iterator *it; | ||
372 | My_Account *acc; | ||
373 | int ret = 0; | ||
374 | |||
375 | if (argc < 3) | ||
376 | { | ||
377 | fprintf(stderr, | ||
378 | "Usage:\n\t%s <input> <output> [action] [action-params]\n\n" | ||
379 | "Where actions and their parameters:\n" | ||
380 | "\tacc <name>\n" | ||
381 | "\tpost <account-name> <message>\n" | ||
382 | "\tmessage <account-name> <message>\n" | ||
383 | "\n", | ||
384 | argv[0]); | ||
385 | return -1; | ||
386 | } | ||
387 | |||
388 | eina_init(); | ||
389 | eet_init(); | ||
390 | _my_cache_descriptor_init(); | ||
391 | |||
392 | my_cache = _my_cache_load(argv[1]); | ||
393 | if (!my_cache) | ||
394 | { | ||
395 | printf("creating new cache.\n"); | ||
396 | my_cache = _my_cache_new(); | ||
397 | if (!my_cache) | ||
398 | { | ||
399 | ret = -2; | ||
400 | goto end; | ||
401 | } | ||
402 | } | ||
403 | |||
404 | if (argc > 3) | ||
405 | { | ||
406 | if (strcmp(argv[3], "acc") == 0) | ||
407 | { | ||
408 | if (argc == 5) | ||
409 | { | ||
410 | My_Account *acc = _my_cache_account_find(my_cache, argv[4]); | ||
411 | if (!acc) | ||
412 | { | ||
413 | acc = _my_account_new(argv[4]); | ||
414 | eina_hash_direct_add(my_cache->accounts, acc->name, acc); | ||
415 | } | ||
416 | else | ||
417 | fprintf(stderr, "ERROR: account '%s' already exists.\n", | ||
418 | argv[4]); | ||
419 | } | ||
420 | else | ||
421 | fprintf(stderr, | ||
422 | "ERROR: wrong number of parameters (%d).\n", | ||
423 | argc); | ||
424 | } | ||
425 | else if (strcmp(argv[3], "post") == 0) | ||
426 | { | ||
427 | if (argc == 6) | ||
428 | { | ||
429 | My_Account *acc = _my_cache_account_find(my_cache, argv[4]); | ||
430 | if (acc) | ||
431 | { | ||
432 | _my_post_add(acc, argv[5]); | ||
433 | } | ||
434 | else | ||
435 | fprintf(stderr, "ERROR: unknown account: '%s'\n", argv[4]); | ||
436 | } | ||
437 | else | ||
438 | fprintf(stderr, | ||
439 | "ERROR: wrong number of parameters (%d).\n", | ||
440 | argc); | ||
441 | } | ||
442 | else if (strcmp(argv[3], "message") == 0) | ||
443 | { | ||
444 | if (argc == 6) | ||
445 | { | ||
446 | My_Account *acc = _my_cache_account_find(my_cache, argv[4]); | ||
447 | if (acc) | ||
448 | { | ||
449 | My_Message *msg = _my_message_new(argv[5]); | ||
450 | acc->messages = eina_list_append(acc->messages, msg); | ||
451 | } | ||
452 | else | ||
453 | fprintf(stderr, "ERROR: unknown account: '%s'\n", argv[4]); | ||
454 | } | ||
455 | else | ||
456 | fprintf(stderr, | ||
457 | "ERROR: wrong number of parameters (%d).\n", | ||
458 | argc); | ||
459 | } | ||
460 | else | ||
461 | fprintf(stderr, "ERROR: unknown action '%s'\n", argv[2]); | ||
462 | } | ||
463 | |||
464 | printf("My_Cache:\n" | ||
465 | "\tversion.: %#x\n" | ||
466 | "\taccounts: %u\n", | ||
467 | my_cache->version, | ||
468 | eina_hash_population(my_cache->accounts)); | ||
469 | it = eina_hash_iterator_data_new(my_cache->accounts); | ||
470 | EINA_ITERATOR_FOREACH(it, acc) | ||
471 | { | ||
472 | const My_Post *post; | ||
473 | |||
474 | printf("\t > %-#8x '%.20s' stats: m=%u, p=%u\n", | ||
475 | acc->id, acc->name ? acc->name : "", | ||
476 | eina_list_count(acc->messages), | ||
477 | acc->posts_count); | ||
478 | |||
479 | if (eina_list_count(acc->messages)) | ||
480 | { | ||
481 | const Eina_List *l; | ||
482 | const My_Message *msg; | ||
483 | printf("\t |messages:\n"); | ||
484 | |||
485 | EINA_LIST_FOREACH(acc->messages, l, msg) | ||
486 | { | ||
487 | printf("\t | %-8x '%s' [%s]: '%.20s'\n", | ||
488 | msg->id, | ||
489 | msg->name ? msg->name : "", | ||
490 | msg->screen_name ? msg->screen_name : "", | ||
491 | msg->message ? msg->message : ""); | ||
492 | } | ||
493 | } | ||
494 | |||
495 | if (acc->posts_count) | ||
496 | { | ||
497 | const My_Post *post; | ||
498 | int i; | ||
499 | printf("\t |posts:\n"); | ||
500 | |||
501 | for (i = 0; i < acc->posts_count; i++) | ||
502 | { | ||
503 | post = &acc->posts[i]; | ||
504 | if (post->dm_to) | ||
505 | printf("\t | @%s: '%.20s'\n", post->dm_to, post->message); | ||
506 | else | ||
507 | printf("\t | '%.20s'\n", post->message); | ||
508 | } | ||
509 | } | ||
510 | |||
511 | printf("\n"); | ||
512 | } | ||
513 | eina_iterator_free(it); | ||
514 | |||
515 | if (!_my_cache_save(my_cache, argv[2])) | ||
516 | ret = -3; | ||
517 | |||
518 | _my_cache_free(my_cache); | ||
519 | |||
520 | end: | ||
521 | if (_my_cache_file) | ||
522 | eet_close(_my_cache_file); | ||
523 | _my_cache_descriptor_shutdown(); | ||
524 | eet_shutdown(); | ||
525 | eina_shutdown(); | ||
526 | |||
527 | return ret; | ||
528 | } /* main */ | ||
529 | |||