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