Tizen Native API
3.0
|
File descriptor data example
00001 //Compile with: 00002 // gcc -o eet-data-file_descriptor_01 eet-data-file_descriptor_01.c `pkg-config --cflags --libs eet eina` 00003 00004 #include <Eina.h> 00005 #include <Eet.h> 00006 #include <stdio.h> 00007 #include <limits.h> 00008 #include <sys/types.h> 00009 #include <sys/stat.h> 00010 #include <unistd.h> 00011 00012 // complex real-world structures based on elmdentica database 00013 typedef struct 00014 { 00015 const char *screen_name; 00016 const char *name; 00017 const char *message; 00018 unsigned int id; 00019 unsigned int status_id; 00020 unsigned int date; 00021 unsigned int timeline; 00022 } My_Message; 00023 00024 typedef struct 00025 { 00026 const char *dm_to; 00027 const char *message; 00028 } My_Post; 00029 00030 typedef struct 00031 { 00032 unsigned int id; 00033 const char *name; 00034 Eina_List *messages; 00035 My_Post *posts; 00036 int posts_count; 00037 } My_Account; 00038 00039 typedef struct 00040 { 00041 unsigned int version; // it is recommended to use versioned configuration! 00042 Eina_Hash *accounts; 00043 } My_Cache; 00044 00045 // string that represents the entry in eet file, you might like to have 00046 // different profiles or so in the same file, this is possible with 00047 // different strings 00048 static const char MY_CACHE_FILE_ENTRY[] = "cache"; 00049 00050 // keep the descriptor static global, so it can be 00051 // shared by different functions (load/save) of this and only this 00052 // file. 00053 static Eet_Data_Descriptor *_my_cache_descriptor; 00054 static Eet_Data_Descriptor *_my_account_descriptor; 00055 static Eet_Data_Descriptor *_my_message_descriptor; 00056 static Eet_Data_Descriptor *_my_post_descriptor; 00057 00058 // keep file handle alive, so mmap()ed strings are all alive as well 00059 static Eet_File *_my_cache_file = NULL; 00060 static Eet_Dictionary *_my_cache_dict = NULL; 00061 00062 static void 00063 _my_cache_descriptor_init(void) 00064 { 00065 Eet_Data_Descriptor_Class eddc; 00066 00067 // The FILE variant is good for caches and things that are just 00068 // appended, but needs to take care when changing strings and files must 00069 // be kept open so mmap()ed strings will be kept alive. 00070 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, My_Cache); 00071 _my_cache_descriptor = eet_data_descriptor_file_new(&eddc); 00072 00073 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, My_Account); 00074 _my_account_descriptor = eet_data_descriptor_file_new(&eddc); 00075 00076 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, My_Message); 00077 _my_message_descriptor = eet_data_descriptor_file_new(&eddc); 00078 00079 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, My_Post); 00080 _my_post_descriptor = eet_data_descriptor_file_new(&eddc); 00081 00082 // Describe the members to be saved: 00083 // Use a temporary macro so we don't type a lot, also avoid errors: 00084 00085 #define ADD_BASIC(member, eet_type) \ 00086 EET_DATA_DESCRIPTOR_ADD_BASIC \ 00087 (_my_message_descriptor, My_Message, # member, member, eet_type) 00088 ADD_BASIC(screen_name, EET_T_STRING); 00089 ADD_BASIC(name, EET_T_STRING); 00090 ADD_BASIC(message, EET_T_STRING); 00091 ADD_BASIC(id, EET_T_UINT); 00092 ADD_BASIC(status_id, EET_T_UINT); 00093 ADD_BASIC(date, EET_T_UINT); 00094 ADD_BASIC(timeline, EET_T_UINT); 00095 #undef ADD_BASIC 00096 00097 #define ADD_BASIC(member, eet_type) \ 00098 EET_DATA_DESCRIPTOR_ADD_BASIC \ 00099 (_my_post_descriptor, My_Post, # member, member, eet_type) 00100 ADD_BASIC(dm_to, EET_T_STRING); 00101 ADD_BASIC(message, EET_T_STRING); 00102 #undef ADD_BASIC 00103 00104 #define ADD_BASIC(member, eet_type) \ 00105 EET_DATA_DESCRIPTOR_ADD_BASIC \ 00106 (_my_account_descriptor, My_Account, # member, member, eet_type) 00107 ADD_BASIC(name, EET_T_STRING); 00108 ADD_BASIC(id, EET_T_UINT); 00109 #undef ADD_BASIC 00110 00111 EET_DATA_DESCRIPTOR_ADD_LIST 00112 (_my_account_descriptor, My_Account, "messages", messages, 00113 _my_message_descriptor); 00114 EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY 00115 (_my_account_descriptor, My_Account, "posts", posts, 00116 _my_post_descriptor); 00117 00118 #define ADD_BASIC(member, eet_type) \ 00119 EET_DATA_DESCRIPTOR_ADD_BASIC \ 00120 (_my_cache_descriptor, My_Cache, # member, member, eet_type) 00121 ADD_BASIC(version, EET_T_UINT); 00122 #undef ADD_BASIC 00123 00124 EET_DATA_DESCRIPTOR_ADD_HASH 00125 (_my_cache_descriptor, My_Cache, "accounts", accounts, 00126 _my_account_descriptor); 00127 } /* _my_cache_descriptor_init */ 00128 00129 static void 00130 _my_cache_descriptor_shutdown(void) 00131 { 00132 eet_data_descriptor_free(_my_cache_descriptor); 00133 eet_data_descriptor_free(_my_account_descriptor); 00134 eet_data_descriptor_free(_my_message_descriptor); 00135 eet_data_descriptor_free(_my_post_descriptor); 00136 } /* _my_cache_descriptor_shutdown */ 00137 00138 // need to check if the pointer came from mmaped area in eet_dictionary 00139 // or it was allocated with eina_stringshare_add() 00140 static void 00141 _eet_string_free(const char *str) 00142 { 00143 if (!str) 00144 return; 00145 00146 if ((_my_cache_dict) && (eet_dictionary_string_check(_my_cache_dict, str))) 00147 return; 00148 00149 eina_stringshare_del(str); 00150 } /* _eet_string_free */ 00151 00152 static My_Message * 00153 _my_message_new(const char *message) 00154 { 00155 My_Message *msg = calloc(1, sizeof(My_Message)); 00156 if (!msg) 00157 { 00158 fprintf(stderr, "ERROR: could not calloc My_Message\n"); 00159 return NULL; 00160 } 00161 00162 msg->message = eina_stringshare_add(message); 00163 return msg; 00164 } /* _my_message_new */ 00165 00166 static void 00167 _my_message_free(My_Message *msg) 00168 { 00169 _eet_string_free(msg->screen_name); 00170 _eet_string_free(msg->name); 00171 _eet_string_free(msg->message); 00172 free(msg); 00173 } /* _my_message_free */ 00174 00175 static Eina_Bool 00176 _my_post_add(My_Account *acc, 00177 const char *message) 00178 { 00179 int new_count = acc->posts_count + 1; 00180 My_Post *post = realloc(acc->posts, new_count * sizeof(My_Post)); 00181 if (!post) 00182 { 00183 fprintf(stderr, "ERROR: could add My_Post\n"); 00184 return EINA_FALSE; 00185 } 00186 00187 post[acc->posts_count].message = eina_stringshare_add(message); 00188 post[acc->posts_count].dm_to = NULL; 00189 acc->posts_count = new_count; 00190 acc->posts = post; 00191 return EINA_TRUE; 00192 } /* _my_post_new */ 00193 00194 static void 00195 _my_post_free(My_Post *post) 00196 { 00197 _eet_string_free(post->dm_to); 00198 _eet_string_free(post->message); 00199 } /* _my_post_free */ 00200 00201 static My_Account * 00202 _my_account_new(const char *name) 00203 { 00204 My_Account *acc = calloc(1, sizeof(My_Account)); 00205 if (!acc) 00206 { 00207 fprintf(stderr, "ERROR: could not calloc My_Account\n"); 00208 return NULL; 00209 } 00210 00211 acc->name = eina_stringshare_add(name); 00212 return acc; 00213 } /* _my_account_new */ 00214 00215 static void 00216 _my_account_free(My_Account *acc) 00217 { 00218 My_Message *m; 00219 int i; 00220 00221 _eet_string_free(acc->name); 00222 00223 EINA_LIST_FREE(acc->messages, m) 00224 _my_message_free(m); 00225 00226 for (i = 0; i < acc->posts_count; i++) 00227 _my_post_free(&acc->posts[i]); 00228 free(acc->posts); 00229 00230 free(acc); 00231 } /* _my_account_free */ 00232 00233 static My_Cache * 00234 _my_cache_new(void) 00235 { 00236 My_Cache *my_cache = calloc(1, sizeof(My_Cache)); 00237 if (!my_cache) 00238 { 00239 fprintf(stderr, "ERROR: could not calloc My_Cache\n"); 00240 return NULL; 00241 } 00242 00243 my_cache->accounts = eina_hash_string_small_new(NULL); 00244 00245 my_cache->version = 1; 00246 return my_cache; 00247 } /* _my_cache_new */ 00248 00249 static Eina_Bool 00250 _my_cache_account_free_cb(const Eina_Hash *hash EINA_UNUSED, 00251 const void *key EINA_UNUSED, 00252 void *data, 00253 void *fdata EINA_UNUSED) 00254 { 00255 _my_account_free(data); 00256 return EINA_TRUE; 00257 } 00258 00259 static void 00260 _my_cache_free(My_Cache *my_cache) 00261 { 00262 eina_hash_foreach(my_cache->accounts, _my_cache_account_free_cb, NULL); 00263 eina_hash_free(my_cache->accounts); 00264 free(my_cache); 00265 } /* _my_cache_free */ 00266 00267 static My_Account * 00268 _my_cache_account_find(My_Cache *my_cache, 00269 const char *name) 00270 { 00271 return eina_hash_find(my_cache->accounts, name); 00272 } /* _my_cache_account_find */ 00273 00274 static My_Cache * 00275 _my_cache_load(const char *filename) 00276 { 00277 My_Cache *my_cache; 00278 Eet_File *ef = eet_open(filename, EET_FILE_MODE_READ); 00279 if (!ef) 00280 { 00281 fprintf(stderr, "ERROR: could not open '%s' for read\n", filename); 00282 return NULL; 00283 } 00284 00285 my_cache = eet_data_read(ef, _my_cache_descriptor, MY_CACHE_FILE_ENTRY); 00286 if (!my_cache) 00287 { 00288 eet_close(ef); 00289 return NULL; 00290 } 00291 00292 if (my_cache->version < 1) 00293 { 00294 fprintf(stderr, 00295 "WARNING: version %#x was too old, upgrading it to %#x\n", 00296 my_cache->version, 1); 00297 00298 my_cache->version = 1; 00299 } 00300 00301 if (_my_cache_file) 00302 eet_close(_my_cache_file); 00303 00304 _my_cache_file = ef; 00305 _my_cache_dict = eet_dictionary_get(ef); 00306 00307 return my_cache; 00308 } /* _my_cache_load */ 00309 00310 static Eina_Bool 00311 _my_cache_save(const My_Cache *my_cache, 00312 const char *filename) 00313 { 00314 char tmp[PATH_MAX]; 00315 Eet_File *ef; 00316 Eina_Bool ret; 00317 unsigned int i, len; 00318 struct stat st; 00319 00320 len = eina_strlcpy(tmp, filename, sizeof(tmp)); 00321 if (len + 12 >= (int)sizeof(tmp)) 00322 { 00323 fprintf(stderr, "ERROR: file name is too big: %s\n", filename); 00324 return EINA_FALSE; 00325 } 00326 00327 i = 0; 00328 do 00329 { 00330 snprintf(tmp + len, 12, ".%u", i); 00331 i++; 00332 } 00333 while (stat(tmp, &st) == 0); 00334 00335 ef = eet_open(tmp, EET_FILE_MODE_WRITE); 00336 if (!ef) 00337 { 00338 fprintf(stderr, "ERROR: could not open '%s' for write\n", tmp); 00339 return EINA_FALSE; 00340 } 00341 00342 ret = eet_data_write 00343 (ef, _my_cache_descriptor, MY_CACHE_FILE_ENTRY, my_cache, EINA_TRUE); 00344 00345 // VERY IMPORTANT NOTE: 00346 // after eet_close(), all strings mmaped from file will be GONE, invalid! 00347 // you'll need to free the old cache and open the new one. 00348 // For cache this is okay, as you should be saving not so often or just 00349 // at end. 00350 // 00351 // This is a trade off, you save memory by using mmap()ed strings, but 00352 // you have to care about this. 00353 eet_close(ef); 00354 00355 if (ret) 00356 { 00357 unlink(filename); 00358 rename(tmp, filename); 00359 } 00360 00361 return ret; 00362 } /* _my_cache_save */ 00363 00364 int 00365 main(int argc, 00366 char *argv[]) 00367 { 00368 My_Cache *my_cache; 00369 Eina_Iterator *it; 00370 My_Account *acc; 00371 int ret = 0; 00372 00373 if (argc < 3) 00374 { 00375 fprintf(stderr, 00376 "Usage:\n\t%s <input> <output> [action] [action-params]\n\n" 00377 "Where actions and their parameters:\n" 00378 "\tacc <name>\n" 00379 "\tpost <account-name> <message>\n" 00380 "\tmessage <account-name> <message>\n" 00381 "\n", 00382 argv[0]); 00383 return -1; 00384 } 00385 00386 eina_init(); 00387 eet_init(); 00388 _my_cache_descriptor_init(); 00389 00390 my_cache = _my_cache_load(argv[1]); 00391 if (!my_cache) 00392 { 00393 printf("creating new cache.\n"); 00394 my_cache = _my_cache_new(); 00395 if (!my_cache) 00396 { 00397 ret = -2; 00398 goto end; 00399 } 00400 } 00401 00402 if (argc > 3) 00403 { 00404 if (strcmp(argv[3], "acc") == 0) 00405 { 00406 if (argc == 5) 00407 { 00408 My_Account *acc_ = _my_cache_account_find(my_cache, argv[4]); 00409 if (!acc_) 00410 { 00411 acc_ = _my_account_new(argv[4]); 00412 eina_hash_direct_add(my_cache->accounts, acc_->name, acc); 00413 } 00414 else 00415 fprintf(stderr, "ERROR: account '%s' already exists.\n", 00416 argv[4]); 00417 } 00418 else 00419 fprintf(stderr, 00420 "ERROR: wrong number of parameters (%d).\n", 00421 argc); 00422 } 00423 else if (strcmp(argv[3], "post") == 0) 00424 { 00425 if (argc == 6) 00426 { 00427 My_Account *acc_ = _my_cache_account_find(my_cache, argv[4]); 00428 if (acc_) 00429 { 00430 _my_post_add(acc_, argv[5]); 00431 } 00432 else 00433 fprintf(stderr, "ERROR: unknown account: '%s'\n", argv[4]); 00434 } 00435 else 00436 fprintf(stderr, 00437 "ERROR: wrong number of parameters (%d).\n", 00438 argc); 00439 } 00440 else if (strcmp(argv[3], "message") == 0) 00441 { 00442 if (argc == 6) 00443 { 00444 My_Account *acc_ = _my_cache_account_find(my_cache, argv[4]); 00445 if (acc_) 00446 { 00447 My_Message *msg = _my_message_new(argv[5]); 00448 acc_->messages = eina_list_append(acc_->messages, msg); 00449 } 00450 else 00451 fprintf(stderr, "ERROR: unknown account: '%s'\n", argv[4]); 00452 } 00453 else 00454 fprintf(stderr, 00455 "ERROR: wrong number of parameters (%d).\n", 00456 argc); 00457 } 00458 else 00459 fprintf(stderr, "ERROR: unknown action '%s'\n", argv[2]); 00460 } 00461 00462 printf("My_Cache:\n" 00463 "\tversion.: %#x\n" 00464 "\taccounts: %u\n", 00465 my_cache->version, 00466 eina_hash_population(my_cache->accounts)); 00467 it = eina_hash_iterator_data_new(my_cache->accounts); 00468 EINA_ITERATOR_FOREACH(it, acc) 00469 { 00470 printf("\t > %-#8x '%.20s' stats: m=%u, p=%u\n", 00471 acc->id, acc->name ? acc->name : "", 00472 eina_list_count(acc->messages), 00473 acc->posts_count); 00474 00475 if (eina_list_count(acc->messages)) 00476 { 00477 const Eina_List *l; 00478 const My_Message *msg; 00479 printf("\t |messages:\n"); 00480 00481 EINA_LIST_FOREACH(acc->messages, l, msg) 00482 { 00483 printf("\t | %-8x '%s' [%s]: '%.20s'\n", 00484 msg->id, 00485 msg->name ? msg->name : "", 00486 msg->screen_name ? msg->screen_name : "", 00487 msg->message ? msg->message : ""); 00488 } 00489 } 00490 00491 if (acc->posts_count) 00492 { 00493 const My_Post *post; 00494 int i; 00495 printf("\t |posts:\n"); 00496 00497 for (i = 0; i < acc->posts_count; i++) 00498 { 00499 post = &acc->posts[i]; 00500 if (post->dm_to) 00501 printf("\t | @%s: '%.20s'\n", post->dm_to, post->message); 00502 else 00503 printf("\t | '%.20s'\n", post->message); 00504 } 00505 } 00506 00507 printf("\n"); 00508 } 00509 eina_iterator_free(it); 00510 00511 if (!_my_cache_save(my_cache, argv[2])) 00512 ret = -3; 00513 00514 _my_cache_free(my_cache); 00515 00516 end: 00517 if (_my_cache_file) 00518 eet_close(_my_cache_file); 00519 _my_cache_descriptor_shutdown(); 00520 eet_shutdown(); 00521 eina_shutdown(); 00522 00523 return ret; 00524 } /* main */ 00525