00001
00002
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
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;
00042 Eina_Hash *accounts;
00043 } My_Cache;
00044
00045
00046
00047
00048 static const char MY_CACHE_FILE_ENTRY[] = "cache";
00049
00050
00051
00052
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
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
00068
00069
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
00083
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 }
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 }
00137
00138
00139
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
00248
00249 static Eina_Bool
00250 _my_cache_account_free_cb(const Eina_Hash *hash,
00251 const void *key,
00252 void *data,
00253 void *fdata)
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 My_Account *acc;
00263 eina_hash_foreach(my_cache->accounts, _my_cache_account_free_cb, NULL);
00264 eina_hash_free(my_cache->accounts);
00265 free(my_cache);
00266 }
00267
00268 static My_Account *
00269 _my_cache_account_find(My_Cache *my_cache,
00270 const char *name)
00271 {
00272 return eina_hash_find(my_cache->accounts, name);
00273 }
00274
00275 static My_Cache *
00276 _my_cache_load(const char *filename)
00277 {
00278 My_Cache *my_cache;
00279 Eet_File *ef = eet_open(filename, EET_FILE_MODE_READ);
00280 if (!ef)
00281 {
00282 fprintf(stderr, "ERROR: could not open '%s' for read\n", filename);
00283 return NULL;
00284 }
00285
00286 my_cache = eet_data_read(ef, _my_cache_descriptor, MY_CACHE_FILE_ENTRY);
00287 if (!my_cache)
00288 {
00289 eet_close(ef);
00290 return NULL;
00291 }
00292
00293 if (my_cache->version < 1)
00294 {
00295 fprintf(stderr,
00296 "WARNING: version %#x was too old, upgrading it to %#x\n",
00297 my_cache->version, 1);
00298
00299 my_cache->version = 1;
00300 }
00301
00302 if (_my_cache_file)
00303 eet_close(_my_cache_file);
00304
00305 _my_cache_file = ef;
00306 _my_cache_dict = eet_dictionary_get(ef);
00307
00308 return my_cache;
00309 }
00310
00311 static Eina_Bool
00312 _my_cache_save(const My_Cache *my_cache,
00313 const char *filename)
00314 {
00315 char tmp[PATH_MAX];
00316 Eet_File *ef;
00317 Eina_Bool ret;
00318 unsigned int i, len;
00319 struct stat st;
00320
00321 len = eina_strlcpy(tmp, filename, sizeof(tmp));
00322 if (len + 12 >= (int)sizeof(tmp))
00323 {
00324 fprintf(stderr, "ERROR: file name is too big: %s\n", filename);
00325 return EINA_FALSE;
00326 }
00327
00328 i = 0;
00329 do
00330 {
00331 snprintf(tmp + len, 12, ".%u", i);
00332 i++;
00333 }
00334 while (stat(tmp, &st) == 0);
00335
00336 ef = eet_open(tmp, EET_FILE_MODE_WRITE);
00337 if (!ef)
00338 {
00339 fprintf(stderr, "ERROR: could not open '%s' for write\n", tmp);
00340 return EINA_FALSE;
00341 }
00342
00343 ret = eet_data_write
00344 (ef, _my_cache_descriptor, MY_CACHE_FILE_ENTRY, my_cache, EINA_TRUE);
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354 eet_close(ef);
00355
00356 if (ret)
00357 {
00358 unlink(filename);
00359 rename(tmp, filename);
00360 }
00361
00362 return ret;
00363 }
00364
00365 int
00366 main(int argc,
00367 char *argv[])
00368 {
00369 My_Cache *my_cache;
00370 const Eina_List *l_acc;
00371 Eina_Iterator *it;
00372 My_Account *acc;
00373 int ret = 0;
00374
00375 if (argc < 3)
00376 {
00377 fprintf(stderr,
00378 "Usage:\n\t%s <input> <output> [action] [action-params]\n\n"
00379 "Where actions and their parameters:\n"
00380 "\tacc <name>\n"
00381 "\tpost <account-name> <message>\n"
00382 "\tmessage <account-name> <message>\n"
00383 "\n",
00384 argv[0]);
00385 return -1;
00386 }
00387
00388 eina_init();
00389 eet_init();
00390 _my_cache_descriptor_init();
00391
00392 my_cache = _my_cache_load(argv[1]);
00393 if (!my_cache)
00394 {
00395 printf("creating new cache.\n");
00396 my_cache = _my_cache_new();
00397 if (!my_cache)
00398 {
00399 ret = -2;
00400 goto end;
00401 }
00402 }
00403
00404 if (argc > 3)
00405 {
00406 if (strcmp(argv[3], "acc") == 0)
00407 {
00408 if (argc == 5)
00409 {
00410 My_Account *acc = _my_cache_account_find(my_cache, argv[4]);
00411 if (!acc)
00412 {
00413 acc = _my_account_new(argv[4]);
00414 eina_hash_direct_add(my_cache->accounts, acc->name, acc);
00415 }
00416 else
00417 fprintf(stderr, "ERROR: account '%s' already exists.\n",
00418 argv[4]);
00419 }
00420 else
00421 fprintf(stderr,
00422 "ERROR: wrong number of parameters (%d).\n",
00423 argc);
00424 }
00425 else if (strcmp(argv[3], "post") == 0)
00426 {
00427 if (argc == 6)
00428 {
00429 My_Account *acc = _my_cache_account_find(my_cache, argv[4]);
00430 if (acc)
00431 {
00432 _my_post_add(acc, argv[5]);
00433 }
00434 else
00435 fprintf(stderr, "ERROR: unknown account: '%s'\n", argv[4]);
00436 }
00437 else
00438 fprintf(stderr,
00439 "ERROR: wrong number of parameters (%d).\n",
00440 argc);
00441 }
00442 else if (strcmp(argv[3], "message") == 0)
00443 {
00444 if (argc == 6)
00445 {
00446 My_Account *acc = _my_cache_account_find(my_cache, argv[4]);
00447 if (acc)
00448 {
00449 My_Message *msg = _my_message_new(argv[5]);
00450 acc->messages = eina_list_append(acc->messages, msg);
00451 }
00452 else
00453 fprintf(stderr, "ERROR: unknown account: '%s'\n", argv[4]);
00454 }
00455 else
00456 fprintf(stderr,
00457 "ERROR: wrong number of parameters (%d).\n",
00458 argc);
00459 }
00460 else
00461 fprintf(stderr, "ERROR: unknown action '%s'\n", argv[2]);
00462 }
00463
00464 printf("My_Cache:\n"
00465 "\tversion.: %#x\n"
00466 "\taccounts: %u\n",
00467 my_cache->version,
00468 eina_hash_population(my_cache->accounts));
00469 it = eina_hash_iterator_data_new(my_cache->accounts);
00470 EINA_ITERATOR_FOREACH(it, acc)
00471 {
00472 const My_Post *post;
00473
00474 printf("\t > %-#8x '%.20s' stats: m=%u, p=%u\n",
00475 acc->id, acc->name ? acc->name : "",
00476 eina_list_count(acc->messages),
00477 acc->posts_count);
00478
00479 if (eina_list_count(acc->messages))
00480 {
00481 const Eina_List *l;
00482 const My_Message *msg;
00483 printf("\t |messages:\n");
00484
00485 EINA_LIST_FOREACH(acc->messages, l, msg)
00486 {
00487 printf("\t | %-8x '%s' [%s]: '%.20s'\n",
00488 msg->id,
00489 msg->name ? msg->name : "",
00490 msg->screen_name ? msg->screen_name : "",
00491 msg->message ? msg->message : "");
00492 }
00493 }
00494
00495 if (acc->posts_count)
00496 {
00497 const My_Post *post;
00498 int i;
00499 printf("\t |posts:\n");
00500
00501 for (i = 0; i < acc->posts_count; i++)
00502 {
00503 post = &acc->posts[i];
00504 if (post->dm_to)
00505 printf("\t | @%s: '%.20s'\n", post->dm_to, post->message);
00506 else
00507 printf("\t | '%.20s'\n", post->message);
00508 }
00509 }
00510
00511 printf("\n");
00512 }
00513 eina_iterator_free(it);
00514
00515 if (!_my_cache_save(my_cache, argv[2]))
00516 ret = -3;
00517
00518 _my_cache_free(my_cache);
00519
00520 end:
00521 if (_my_cache_file)
00522 eet_close(_my_cache_file);
00523 _my_cache_descriptor_shutdown();
00524 eet_shutdown();
00525 eina_shutdown();
00526
00527 return ret;
00528 }
00529