9 // complex real-world structures based on elmdentica database
11 const char *screen_name;
15 unsigned int status_id;
17 unsigned int timeline;
33 unsigned int version; // it is recommended to use versioned configuration!
37 // string that represents the entry in eet file, you might like to have
38 // different profiles or so in the same file, this is possible with
40 static const char MY_CACHE_FILE_ENTRY[] = "cache";
42 // keep the descriptor static global, so it can be
43 // shared by different functions (load/save) of this and only this
45 static Eet_Data_Descriptor *_my_cache_descriptor;
46 static Eet_Data_Descriptor *_my_account_descriptor;
47 static Eet_Data_Descriptor *_my_message_descriptor;
48 static Eet_Data_Descriptor *_my_post_descriptor;
50 // keep file handle alive, so mmap()ed strings are all alive as well
51 static Eet_File *_my_cache_file = NULL;
52 static Eet_Dictionary *_my_cache_dict = NULL;
55 _my_cache_descriptor_init(void)
57 Eet_Data_Descriptor_Class eddc;
59 // The FILE variant is good for caches and things that are just
60 // appended, but needs to take care when changing strings and files must
61 // be kept open so mmap()ed strings will be kept alive.
62 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, My_Cache);
63 _my_cache_descriptor = eet_data_descriptor_file_new(&eddc);
65 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, My_Account);
66 _my_account_descriptor = eet_data_descriptor_file_new(&eddc);
68 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, My_Message);
69 _my_message_descriptor = eet_data_descriptor_file_new(&eddc);
71 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, My_Post);
72 _my_post_descriptor = eet_data_descriptor_file_new(&eddc);
74 // Describe the members to be saved:
75 // Use a temporary macro so we don't type a lot, also avoid errors:
77 #define ADD_BASIC(member, eet_type) \
78 EET_DATA_DESCRIPTOR_ADD_BASIC \
79 (_my_message_descriptor, My_Message, #member, member, eet_type)
80 ADD_BASIC(screen_name, EET_T_STRING);
81 ADD_BASIC(name, EET_T_STRING);
82 ADD_BASIC(message, EET_T_STRING);
83 ADD_BASIC(id, EET_T_UINT);
84 ADD_BASIC(status_id, EET_T_UINT);
85 ADD_BASIC(date, EET_T_UINT);
86 ADD_BASIC(timeline, EET_T_UINT);
89 #define ADD_BASIC(member, eet_type) \
90 EET_DATA_DESCRIPTOR_ADD_BASIC \
91 (_my_post_descriptor, My_Post, #member, member, eet_type)
92 ADD_BASIC(dm_to, EET_T_STRING);
93 ADD_BASIC(message, EET_T_STRING);
96 #define ADD_BASIC(member, eet_type) \
97 EET_DATA_DESCRIPTOR_ADD_BASIC \
98 (_my_account_descriptor, My_Account, #member, member, eet_type)
99 ADD_BASIC(name, EET_T_STRING);
100 ADD_BASIC(id, EET_T_UINT);
103 EET_DATA_DESCRIPTOR_ADD_LIST
104 (_my_account_descriptor, My_Account, "messages", messages,
105 _my_message_descriptor);
106 EET_DATA_DESCRIPTOR_ADD_LIST
107 (_my_account_descriptor, My_Account, "posts", posts,
108 _my_post_descriptor);
110 #define ADD_BASIC(member, eet_type) \
111 EET_DATA_DESCRIPTOR_ADD_BASIC \
112 (_my_cache_descriptor, My_Cache, #member, member, eet_type)
113 ADD_BASIC(version, EET_T_UINT);
116 EET_DATA_DESCRIPTOR_ADD_LIST
117 (_my_cache_descriptor, My_Cache, "accounts", accounts,
118 _my_account_descriptor);
122 _my_cache_descriptor_shutdown(void)
124 eet_data_descriptor_free(_my_cache_descriptor);
125 eet_data_descriptor_free(_my_account_descriptor);
126 eet_data_descriptor_free(_my_message_descriptor);
127 eet_data_descriptor_free(_my_post_descriptor);
130 // need to check if the pointer came from mmaped area in eet_dictionary
131 // or it was allocated with eina_stringshare_add()
133 _eet_string_free(const char *str)
137 if ((_my_cache_dict) && (eet_dictionary_string_check(_my_cache_dict, str)))
139 eina_stringshare_del(str);
143 _my_message_new(const char *message)
145 My_Message *msg = calloc(1, sizeof(My_Message));
148 fprintf(stderr, "ERROR: could not calloc My_Message\n");
151 msg->message = eina_stringshare_add(message);
156 _my_message_free(My_Message *msg)
158 _eet_string_free(msg->screen_name);
159 _eet_string_free(msg->name);
160 _eet_string_free(msg->message);
165 _my_post_new(const char *message)
167 My_Post *post = calloc(1, sizeof(My_Post));
170 fprintf(stderr, "ERROR: could not calloc My_Post\n");
173 post->message = eina_stringshare_add(message);
178 _my_post_free(My_Post *post)
180 _eet_string_free(post->dm_to);
181 _eet_string_free(post->message);
186 _my_account_new(const char *name)
188 My_Account *acc = calloc(1, sizeof(My_Account));
191 fprintf(stderr, "ERROR: could not calloc My_Account\n");
194 acc->name = eina_stringshare_add(name);
199 _my_account_free(My_Account *acc)
204 _eet_string_free(acc->name);
206 EINA_LIST_FREE(acc->messages, m)
209 EINA_LIST_FREE(acc->posts, p)
218 My_Cache *my_cache = calloc(1, sizeof(My_Cache));
221 fprintf(stderr, "ERROR: could not calloc My_Cache\n");
225 my_cache->version = 1;
230 _my_cache_free(My_Cache *my_cache)
233 EINA_LIST_FREE(my_cache->accounts, acc)
234 _my_account_free(acc);
239 _my_cache_account_find(My_Cache *my_cache, const char *name)
243 EINA_LIST_FOREACH(my_cache->accounts, l, acc)
244 if (strcmp(acc->name, name) == 0)
250 _my_cache_load(const char *filename)
253 Eet_File *ef = eet_open(filename, EET_FILE_MODE_READ);
256 fprintf(stderr, "ERROR: could not open '%s' for read\n", filename);
260 my_cache = eet_data_read(ef, _my_cache_descriptor, MY_CACHE_FILE_ENTRY);
267 if (my_cache->version < 1)
270 "WARNING: version %#x was too old, upgrading it to %#x\n",
271 my_cache->version, 1);
273 my_cache->version = 1;
277 eet_close(_my_cache_file);
279 _my_cache_dict = eet_dictionary_get(ef);
285 _my_cache_save(const My_Cache *my_cache, const char *filename)
293 len = eina_strlcpy(tmp, filename, sizeof(tmp));
294 if (len + 12 >= (int)sizeof(tmp))
296 fprintf(stderr, "ERROR: file name is too big: %s\n", filename);
303 snprintf(tmp + len, 12, ".%u", i);
306 while (stat(tmp, &st) == 0);
308 ef = eet_open(tmp, EET_FILE_MODE_WRITE);
311 fprintf(stderr, "ERROR: could not open '%s' for write\n", tmp);
316 (ef, _my_cache_descriptor, MY_CACHE_FILE_ENTRY, my_cache, EINA_TRUE);
318 // VERY IMPORTANT NOTE:
319 // after eet_close(), all strings mmaped from file will be GONE, invalid!
320 // you'll need to free the old cache and open the new one.
321 // For cache this is okay, as you should be saving not so often or just
324 // This is a trade off, you save memory by using mmap()ed strings, but
325 // you have to care about this.
331 rename(tmp, filename);
337 int main(int argc, char *argv[])
340 const Eina_List *l_acc;
347 "Usage:\n\t%s <input> <output> [action] [action-params]\n\n"
348 "Where actions and their parameters:\n"
350 "\tpost <account-name> <message>\n"
351 "\tmessage <account-name> <message>\n"
359 _my_cache_descriptor_init();
361 my_cache = _my_cache_load(argv[1]);
364 printf("creating new cache.\n");
365 my_cache = _my_cache_new();
375 if (strcmp(argv[3], "acc") == 0)
379 My_Account *acc = _my_cache_account_find(my_cache, argv[4]);
382 acc = _my_account_new(argv[4]);
383 my_cache->accounts = eina_list_append
384 (my_cache->accounts, acc);
387 fprintf(stderr, "ERROR: account '%s' already exists.\n",
391 fprintf(stderr, "ERROR: wrong number of parameters (%d).\n",
394 else if (strcmp(argv[3], "post") == 0)
398 My_Account *acc = _my_cache_account_find(my_cache, argv[4]);
401 My_Post *post = _my_post_new(argv[5]);
402 acc->posts = eina_list_append(acc->posts, post);
405 fprintf(stderr, "ERROR: unknown account: '%s'\n", argv[4]);
408 fprintf(stderr, "ERROR: wrong number of parameters (%d).\n",
411 else if (strcmp(argv[3], "message") == 0)
415 My_Account *acc = _my_cache_account_find(my_cache, argv[4]);
418 My_Message *msg = _my_message_new(argv[5]);
419 acc->messages = eina_list_append(acc->messages, msg);
422 fprintf(stderr, "ERROR: unknown account: '%s'\n", argv[4]);
425 fprintf(stderr, "ERROR: wrong number of parameters (%d).\n",
429 fprintf(stderr, "ERROR: unknown action '%s'\n", argv[2]);
436 eina_list_count(my_cache->accounts));
437 EINA_LIST_FOREACH(my_cache->accounts, l_acc, acc)
441 printf("\t > %-#8x '%.20s' stats: m=%u, p=%u\n",
442 acc->id, acc->name ? acc->name : "",
443 eina_list_count(acc->messages),
444 eina_list_count(acc->posts));
446 if (eina_list_count(acc->messages))
449 const My_Message *msg;
450 printf("\t |messages:\n");
452 EINA_LIST_FOREACH(acc->messages, l, msg)
454 printf("\t | %-8x '%s' [%s]: '%.20s'\n",
456 msg->name ? msg->name : "",
457 msg->screen_name ? msg->screen_name : "",
458 msg->message ? msg->message : "");
462 if (eina_list_count(acc->posts))
466 printf("\t |posts:\n");
468 EINA_LIST_FOREACH(acc->posts, l, post)
471 printf("\t | @%s: '%.20s'\n", post->dm_to, post->message);
473 printf("\t | '%.20s'\n", post->message);
479 if (!_my_cache_save(my_cache, argv[2]))
482 _my_cache_free(my_cache);
485 _my_cache_descriptor_shutdown();