52a095d3c10df0099d0b4dcbddf71f2de76056d6
[framework/uifw/eet.git] / src / examples / eet-data-nested.c
1 #include <Eina.h>
2 #include <Eet.h>
3 #include <stdio.h>
4 #include <limits.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <unistd.h>
8
9 // The struct that will be loaded and saved.
10 // note that only the members described in the eet_data_descriptor
11 // will be automatically handled. The other members will have their
12 // space reserved and zeroed (as it uses calloc()), but not
13 // saved or loaded from eet files.
14 typedef struct {
15    unsigned int version; // it is recommended to use versioned configuration!
16    const char *name;
17    int id;
18    int not_saved_value; // example of not saved data inside!
19    Eina_Bool enabled;
20    Eina_List *subs;
21 } My_Conf_Type;
22
23 typedef struct {
24    const char *server;
25    int port;
26 } My_Conf_Subtype;
27
28 // string that represents the entry in eet file, you might like to have
29 // different profiles or so in the same file, this is possible with
30 // different strings
31 static const char MY_CONF_FILE_ENTRY[] = "config";
32
33
34 // keep the descriptor static global, so it can be
35 // shared by different functions (load/save) of this and only this
36 // file.
37 static Eet_Data_Descriptor *_my_conf_descriptor;
38 static Eet_Data_Descriptor *_my_conf_sub_descriptor;
39
40 static void
41 _my_conf_descriptor_init(void)
42 {
43    Eet_Data_Descriptor_Class eddc;
44
45    // The class describe the functions to use to create the type and its
46    // full allocated size.
47    //
48    // Eina types are very convenient, so use them to create the descriptor,
49    // so we get eina_list,  eina_hash and eina_stringshare automatically!
50    //
51    // The STREAM variant is better for configuration files as the values
52    // will likely change a lot.
53    //
54    // The other variant, FILE, is good for caches and things that are just
55    // appended, but needs to take care when changing strings and files must
56    // be kept open so mmap()ed strings will be kept alive.
57    EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, My_Conf_Type);
58    _my_conf_descriptor = eet_data_descriptor_stream_new(&eddc);
59
60    EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, My_Conf_Subtype);
61    _my_conf_sub_descriptor = eet_data_descriptor_stream_new(&eddc);
62
63    // Describe the members to be saved:
64    // Use a temporary macro so we don't type a lot, also avoid errors:
65 #define MY_CONF_ADD_BASIC(member, eet_type)                             \
66    EET_DATA_DESCRIPTOR_ADD_BASIC                                        \
67      (_my_conf_descriptor, My_Conf_Type, #member, member, eet_type)
68 #define MY_CONF_SUB_ADD_BASIC(member, eet_type)                         \
69    EET_DATA_DESCRIPTOR_ADD_BASIC                                        \
70      (_my_conf_sub_descriptor, My_Conf_Subtype, #member, member, eet_type)
71
72    MY_CONF_SUB_ADD_BASIC(server, EET_T_STRING);
73    MY_CONF_SUB_ADD_BASIC(port, EET_T_INT);
74
75    MY_CONF_ADD_BASIC(version, EET_T_UINT);
76    MY_CONF_ADD_BASIC(name, EET_T_STRING);
77    MY_CONF_ADD_BASIC(id, EET_T_INT);
78    MY_CONF_ADD_BASIC(enabled, EET_T_UCHAR);
79
80    // And add the sub descriptor as a linked list at 'subs' in the main struct
81    EET_DATA_DESCRIPTOR_ADD_LIST
82      (_my_conf_descriptor, My_Conf_Type, "subs", subs, _my_conf_sub_descriptor);
83
84 #undef MY_CONF_ADD_BASIC
85 #undef MY_CONF_SUB_ADD_BASIC
86 }
87
88 static void
89 _my_conf_descriptor_shutdown(void)
90 {
91    eet_data_descriptor_free(_my_conf_sub_descriptor);
92    eet_data_descriptor_free(_my_conf_descriptor);
93 }
94
95 static My_Conf_Type *
96 _my_conf_new(void)
97 {
98    My_Conf_Type *my_conf = calloc(1, sizeof(My_Conf_Type));
99    My_Conf_Subtype *sub;
100    if (!my_conf)
101      {
102         fprintf(stderr, "ERROR: could not calloc My_Conf_Type\n");
103         return NULL;
104      }
105
106    my_conf->version = 0x112233;
107    my_conf->enabled = EINA_TRUE;
108
109    sub = calloc(1, sizeof(My_Conf_Subtype));
110    if (sub)
111      {
112         sub->server = eina_stringshare_add("my-server.com");
113         sub->port = 1234;
114         my_conf->subs = eina_list_append(my_conf->subs, sub);
115      }
116
117    return my_conf;
118 }
119
120 static void
121 _my_conf_free(My_Conf_Type *my_conf)
122 {
123    My_Conf_Subtype *sub;
124    EINA_LIST_FREE(my_conf->subs, sub)
125      {
126         eina_stringshare_del(sub->server);
127         free(sub);
128      }
129
130    eina_stringshare_del(my_conf->name);
131    free(my_conf);
132 }
133
134 static My_Conf_Type *
135 _my_conf_load(const char *filename)
136 {
137    My_Conf_Type *my_conf;
138    Eet_File *ef = eet_open(filename, EET_FILE_MODE_READ);
139    if (!ef)
140      {
141         fprintf(stderr, "ERROR: could not open '%s' for read\n", filename);
142         return NULL;
143      }
144
145    my_conf = eet_data_read(ef, _my_conf_descriptor, MY_CONF_FILE_ENTRY);
146    if (!my_conf)
147      goto end;
148
149    if (my_conf->version < 0x112233)
150      {
151         fprintf(stderr,
152                 "WARNING: version %#x was too old, upgrading it to %#x\n",
153                 my_conf->version, 0x112233);
154
155         my_conf->version = 0x112233;
156         my_conf->enabled = EINA_TRUE;
157      }
158
159  end:
160    eet_close(ef);
161    return my_conf;
162 }
163
164 static Eina_Bool
165 _my_conf_save(const My_Conf_Type *my_conf, const char *filename)
166 {
167    char tmp[PATH_MAX];
168    Eet_File *ef;
169    Eina_Bool ret;
170    unsigned int i, len;
171    struct stat st;
172
173    len = eina_strlcpy(tmp, filename, sizeof(tmp));
174    if (len + 12 >= (int)sizeof(tmp))
175      {
176         fprintf(stderr, "ERROR: file name is too big: %s\n", filename);
177         return EINA_FALSE;
178      }
179
180    i = 0;
181    do
182      {
183         snprintf(tmp + len, 12, ".%u", i);
184         i++;
185      }
186    while (stat(tmp, &st) == 0);
187
188    ef = eet_open(tmp, EET_FILE_MODE_WRITE);
189    if (!ef)
190      {
191         fprintf(stderr, "ERROR: could not open '%s' for write\n", tmp);
192         return EINA_FALSE;
193      }
194
195    ret = eet_data_write
196      (ef, _my_conf_descriptor, MY_CONF_FILE_ENTRY, my_conf, EINA_TRUE);
197    eet_close(ef);
198
199    if (ret)
200      {
201         unlink(filename);
202         rename(tmp, filename);
203      }
204
205    return ret;
206 }
207
208 int main(int argc, char *argv[])
209 {
210    My_Conf_Type *my_conf;
211    const My_Conf_Subtype *sub;
212    const Eina_List *l;
213    int ret = 0;
214
215    if (argc != 3)
216      {
217         fprintf(stderr, "Usage:\n\t%s <input> <output>\n\n", argv[0]);
218         return -1;
219      }
220
221    eina_init();
222    eet_init();
223    _my_conf_descriptor_init();
224
225    my_conf = _my_conf_load(argv[1]);
226    if (!my_conf)
227      {
228         printf("creating new configuration.\n");
229         my_conf = _my_conf_new();
230         if (!my_conf)
231           {
232              ret = -2;
233              goto end;
234           }
235      }
236
237    printf("My_Conf_Type:\n"
238           "\tversion: %#x\n"
239           "\tname...: '%s'\n"
240           "\tid.....: %d\n"
241           "\tenabled: %hhu\n"
242           "\tsubs...:\n",
243           my_conf->version,
244           my_conf->name ? my_conf->name : "",
245           my_conf->id,
246           my_conf->enabled);
247
248    EINA_LIST_FOREACH(my_conf->subs, l, sub)
249      printf("\t\tserver: '%s', port: %d\n",
250             sub->server ? sub->server : "",
251             sub->port);
252
253    if (!_my_conf_save(my_conf, argv[2]))
254      ret = -3;
255
256    _my_conf_free(my_conf);
257
258  end:
259    _my_conf_descriptor_shutdown();
260    eet_shutdown();
261    eina_shutdown();
262
263    return ret;
264 }